diff options
Diffstat (limited to 'source/xap/xv/xv-3.10a-jumbo-enh-patch-20050501.txt')
-rw-r--r-- | source/xap/xv/xv-3.10a-jumbo-enh-patch-20050501.txt | 28167 |
1 files changed, 28167 insertions, 0 deletions
diff --git a/source/xap/xv/xv-3.10a-jumbo-enh-patch-20050501.txt b/source/xap/xv/xv-3.10a-jumbo-enh-patch-20050501.txt new file mode 100644 index 00000000..d78b601a --- /dev/null +++ b/source/xap/xv/xv-3.10a-jumbo-enh-patch-20050501.txt @@ -0,0 +1,28167 @@ +diff : xv-3.10a-jumbo-enh-patch-20050501.txt + +This is a unified diff. It should be applied (using Larry Wall's "patch" +program) to the XV 3.10a sources AFTER the jumbo-fixes patch has already +been applied. + +diffs below: + Imakefile + Makefile + Makefile.std + README.jumbo + README.pcd + bggen.c + bits/br_bzip2 + bits/br_mag + bits/br_maki + bits/br_mgcsfx + bits/br_pcd + bits/br_pi + bits/br_pic + bits/br_pic2 + bits/br_png + bits/br_zx + config.h + tiff/Makefile + vdcomp.c + xcmap.c + xv.c + xv.h + xv_mgcsfx.sample + xvbmp.c + xvbrowse.c + xvctrl.c + xvdial.c + xvdir.c + xvevent.c + xvfits.c + xvgam.c + xvgif.c + xvgrab.c + xvhips.c + xvhips.h + xvimage.c + xvinfo.c + xvjpeg.c + xvmag.c + xvmaki.c + xvmgcsfx.c + xvmisc.c + xvml.c + xvml.h + xvpbm.c + xvpcd.c + xvpds.c + xvpi.c + xvpic.c + xvpic2.c + xvpng.c + xvpopup.c + xvps.c + xvrle.c + xvroot.c + xvsmooth.c + xvtext.c + xvtiff.c + xvtiffwr.c + xvvd.c + xvwbmp.c + xvxpm.c + xvzx.c + + +diff -ruN xv-3.10a-bugfixes/Imakefile xv-3.10a-enhancements/Imakefile +--- xv-3.10a-bugfixes/Imakefile 1995-01-13 12:24:01.000000000 -0800 ++++ xv-3.10a-enhancements/Imakefile 2005-04-17 14:04:22.000000000 -0700 +@@ -104,6 +104,11 @@ + SGI = -Dsgi + #endif + ++/* install directory of xv_mgcsfx.sample. */ ++MGCSFXDIR = $(LIBDIR) ++/* Directory of default configuration file. */ ++MGCSFX = -DMGCSFXDIR=\"$(MGCSFXDIR)\" ++ + + + +@@ -137,6 +142,8 @@ + #if defined(SCOArchitecture) + SCO= -Dsco -DPOSIX -DNO_RANDOM + SYS_LIBRARIES= -lm -lc -lx ++#elif defined(HPArchitecture) ++SYS_LIBRARIES= -lm -lV3 + #else + SYS_LIBRARIES= -lm + #endif +@@ -147,7 +154,7 @@ + + DEFINES= $(SCO) $(UNIX) $(NODIRENT) $(VPRINTF) $(TIMERS) \ + $(HPUX7) $(JPEG) $(TIFF) $(PDS) $(DXWM) $(RAND) \ +- $(BACKING_STORE) $(BSDTYPES) $(SGI) ++ $(BACKING_STORE) $(BSDTYPES) $(SGI) $(MGCSFX) + + INCLUDES = $(JPEGINCLUDE) $(TIFFINCLUDE) + +@@ -157,7 +164,9 @@ + xvdial.c xvgraf.c xvsunras.c xvjpeg.c xvps.c xvpopup.c xvdflt.c \ + xvtiff.c xvtiffwr.c xvpds.c xvrle.c xviris.c xvgrab.c vprintf.c \ + xvbrowse.c xvtext.c xvpcx.c xviff.c xvtarga.c xvxpm.c xvcut.c \ +- xvxwd.c xvfits.c ++ xvxwd.c xvfits.c xvpng.c xvzx.c xvwbmp.c xvpcd.c \ ++ xvmag.c xvpic.c xvmaki.c xvpi.c xvpic2.c xvvd.c xvmgcsfx.c \ ++ xvml.c + + OBJS1 = xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \ + xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \ +@@ -165,7 +174,9 @@ + xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \ + xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \ + xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \ +- xvxwd.o xvfits.o ++ xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o \ ++ xvmag.o xvpic.o xvmaki.o xvpi.o xvpic2.o xvvd.o xvmgcsfx.o \ ++ xvml.o + + SRCS2= bggen.c + OBJS2= bggen.o +@@ -266,6 +277,8 @@ + InstallManPageLong(docs/xvp2p,$(MANDIR),xvpictoppm) + InstallManPageLong(docs/vdcomp,$(MANDIR),vdcomp) + ++InstallNonExecFile(xv_mgcsfx.sample,$(MGCSFXDIR)) ++ + tar: + tar cf xv.tar Makefile* Imakefile *.c *.h bits docs \ + docs unsupt vms $(JPEGDIR) $(TIFFDIR) $(MISC) +diff -ruN xv-3.10a-bugfixes/Makefile xv-3.10a-enhancements/Makefile +--- xv-3.10a-bugfixes/Makefile 2005-04-06 08:17:13.000000000 -0700 ++++ xv-3.10a-enhancements/Makefile 2005-05-01 10:23:32.000000000 -0700 +@@ -41,10 +41,14 @@ + + + ### Installation locations +-BINDIR = /usr/local/bin +-MANDIR = /usr/local/man/man1 ++PREFIX = /usr/local ++BINDIR = $(PREFIX)/bin ++MANDIR = $(PREFIX)/man/man1 + MANSUF = 1 +-LIBDIR = /usr/local/lib ++DOCDIR = $(PREFIX)/doc/xv-3.10a ++LIBDIR = $(PREFIX)/lib/xv ++SYSCONFDIR = $(PREFIX)/etc ++DESTDIR = + + + buildit: all +@@ -59,13 +63,59 @@ + ### on your machine, *COMMENT OUT* the following lines + ### + JPEG = -DDOJPEG +-JPEGDIR = jpeg +-JPEGINC = -I$(JPEGDIR) +-JPEGLIB = $(JPEGDIR)/libjpeg.a +-$(JPEGDIR)/jconfig.h: +- cd $(JPEGDIR) ; ./configure CC='$(CC)' +-$(JPEGLIB): $(JPEGDIR)/jconfig.h +- cd $(JPEGDIR) ; make ++#JPEGDIR = jpeg ++JPEGDIR = /usr ++#JPEGDIR = /usr/local ++#JPEGDIR = ../../libjpeg ++### ++JPEGINC = -I$(JPEGDIR)/include ++#JPEGINC = -I$(JPEGDIR) ++### ++JPEGLIB = -L$(JPEGDIR)/lib -ljpeg ++#JPEGLIB = -L$(JPEGDIR) -ljpeg ++#JPEGLIB = $(JPEGDIR)/libjpeg.a ++### ++### this is intended to build the ancient version (5a) that's included in the ++### "jpeg" subdir of XV, not an arbitrary copy of libjpeg: ++### ++#$(JPEGDIR)/jconfig.h: ++# cd $(JPEGDIR) ; ./configure CC='$(CC)' ++#$(JPEGLIB): $(JPEGDIR)/jconfig.h ++# cd $(JPEGDIR) ; make ++ ++ ++### ++### if, for whatever reason, you're unable to get the PNG library to compile ++### on your machine, *COMMENT OUT* the following lines ++### ++PNG = -DDOPNG ++PNGDIR = /usr ++#PNGDIR = /usr/local ++#PNGDIR = ../../libpng ++### ++PNGINC = -I$(PNGDIR)/include ++#PNGINC = -I$(PNGDIR) ++### ++PNGLIB = -L$(PNGDIR)/lib -lpng ++#PNGLIB = -L$(PNGDIR) -lpng ++#PNGLIB = $(PNGDIR)/libpng.a ++ ++ ++### ++### if, for whatever reason, you're unable to get both the PNG library and ++### (newer versions of) the TIFF library to compile on your machine, *COMMENT ++### OUT* the following lines ++### ++ZLIBDIR = /usr ++#ZLIBDIR = /usr/local ++#ZLIBDIR = ../../zlib ++### ++ZLIBINC = -I$(ZLIBDIR)/include ++#ZLIBINC = -I$(ZLIBDIR) ++### ++ZLIBLIB = -L$(ZLIBDIR)/lib -lz ++#ZLIBLIB = -L$(ZLIBDIR) -lz ++#ZLIBLIB = $(ZLIBDIR)/libz.a + + + ### +@@ -80,17 +130,32 @@ + ### + #TIFF = -DDOTIFF + TIFF = -DDOTIFF -DUSE_TILED_TIFF_BOTLEFT_FIX +-TIFFDIR = tiff +-TIFFINC = -I$(TIFFDIR) +-TIFFLIB = $(TIFFDIR)/libtiff.a +-$(TIFFLIB): +- ( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' ) ++#TIFFDIR = tiff ++TIFFDIR = /usr ++#TIFFDIR = /usr/local ++#TIFFDIR = ../../libtiff ++### ++TIFFINC = -I$(TIFFDIR)/include ++#TIFFINC = -I$(TIFFDIR) ++### ++### libtiff 3.5 and up may be compiled with zlib and libjpeg, but dependency ++### is properly handled in LIBS line ~143 lines below ++### ++TIFFLIB = -L$(TIFFDIR)/lib -ltiff ++#TIFFLIB = -L$(TIFFDIR) -ltiff ++#TIFFLIB = $(TIFFDIR)/libtiff.a ++### ++### this is intended to build the ancient version (3.3.016 beta) that's included ++### in the "tiff" subdir of XV, not an arbitrary copy of libtiff: ++### ++#$(TIFFLIB): ++# ( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' ) + + + ### + ### if, for whatever reason, you're unable to get the PDS/VICAR support + ### to compile (xvpds.c, and vdcomp.c), *COMMENT OUT* the following line, +-### and also remove 'vdcomp' from the 'all:' dependancy ++### and also remove 'vdcomp' from the 'all:' dependency + ### + PDS = -DDOPDS + +@@ -98,8 +163,10 @@ + #----------System V---------- + + # if you are running on a SysV-based machine, such as HP, Silicon Graphics, +-# Solaris, etc., uncomment the following line to get mostly there. +-#UNIX = -DSVR4 ++# Solaris, etc.; uncomment one of the following lines to get you *most* of ++# the way there. SYSV means System V R3. ++# UNIX = -DSVR4 ++# UNIX = -DSYSV + + + #----------Machine-Specific Configurations---------- +@@ -121,12 +188,15 @@ + # To use old HP compilers (HPUX 7.0 or so), you may need + #MCHN= -Dhpux -D_HPUX_SOURCE +Ns4000 + # +-# also, if you're using HP's compiler, add '-Aa' to whichever of those ++# Also, if you're using HP's compiler, add '-Aa' to whichever of those + # two lines you're using, to turn on ANSI C mode. Or so I'm told. + # +-# note: You may need to add '-I/usr/include/X11R5' (or R6, or whatever) ++# Note: You may need to add '-I/usr/include/X11R5' (or R6, or whatever) + # to whichever of those lines you used, as HP tends to store their X11 + # include files in a non-standard place... ++# ++# And you probably have to add '-lV3' to the end of the LIBS def when ++# using XV's AUTO_EXPAND option. + + + ### for LINUX, uncomment the following line +@@ -205,6 +275,16 @@ + #VPRINTF = -DNEED_VPRINTF -DLONGINT -DNOSTDHDRS + + ++# if your X Window System compiled with -DX_LOCALE, ++# uncomment the following line: ++# TVL10N = -DX_LOCALE ++ ++# Install directory of xv_mgcsfx.sample. ++MGCSFXDIR = $(LIBDIR) ++# Directory of default configuration file. ++MGCSFX = -DMGCSFXDIR=\"$(MGCSFXDIR)\" ++ ++ + + + ################ END OF CONFIGURATION OPTIONS ################# +@@ -212,13 +292,14 @@ + + + +-CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \ +- $(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \ +- $(DXWM) $(MCHN) ++CFLAGS = $(CCOPTS) $(PNG) $(PNGINC) $(ZLIBINC) $(JPEG) $(JPEGINC) \ ++ $(TIFF) $(TIFFINC) $(PDS) $(NODIRENT) $(VPRINTF) $(TIMERS) \ ++ $(UNIX) $(BSDTYPES) $(RAND) $(DXWM) $(MCHN) $(TVL10N) $(MGCSFX) \ ++ -DSYSCONFDIR=\"$(SYSCONFDIR)\" -DXVEXECPATH=\"$(LIBDIR)\" + + ### remove -lm for BeOS: +-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm +-#LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) ++LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -L/usr/X11R6/lib -lX11 -lm ++#LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -lX11 + + OBJS = xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \ + xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \ +@@ -226,7 +307,9 @@ + xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \ + xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \ + xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \ +- xvxwd.o xvfits.o ++ xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o xvhips.o \ ++ xvmag.o xvpic.o xvmaki.o xvpi.o xvpic2.o xvvd.o xvmgcsfx.o \ ++ xvml.o + + MISC = README INSTALL CHANGELOG IDEAS + +@@ -236,10 +319,12 @@ + + + +-all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm ++#all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm ++all: xv bggen vdcomp xcmap xvpictoppm + + +-xv: $(OBJS) $(JPEGLIB) $(TIFFLIB) ++#xv: $(OBJS) $(JPEGLIB) $(TIFFLIB) ++xv: $(OBJS) + $(CC) -o xv $(CFLAGS) $(OBJS) $(LIBS) + + bggen: bggen.c +@@ -268,13 +353,14 @@ + + + install: all +- cp xv bggen vdcomp xcmap xvpictoppm $(BINDIR) +- cp docs/xv.man $(MANDIR)/xv.$(MANSUF) +- cp docs/bggen.man $(MANDIR)/bggen.$(MANSUF) +- cp docs/xcmap.man $(MANDIR)/xcmap.$(MANSUF) +- cp docs/xvp2p.man $(MANDIR)/xvpictoppm.$(MANSUF) +- cp docs/vdcomp.man $(MANDIR)/vdcomp.$(MANSUF) +- cp docs/xvdocs.ps* $(LIBDIR) ++ cp xv bggen vdcomp xcmap xvpictoppm $(DESTDIR)$(BINDIR) ++ cp docs/xv.man $(DESTDIR)$(MANDIR)/xv.$(MANSUF) ++ cp docs/bggen.man $(DESTDIR)$(MANDIR)/bggen.$(MANSUF) ++ cp docs/xcmap.man $(DESTDIR)$(MANDIR)/xcmap.$(MANSUF) ++ cp docs/xvp2p.man $(DESTDIR)$(MANDIR)/xvpictoppm.$(MANSUF) ++ cp docs/vdcomp.man $(DESTDIR)$(MANDIR)/vdcomp.$(MANSUF) ++ cp docs/xvdocs.ps* $(DESTDIR)$(LIBDIR) # or $(DESTDIR)$(DOCDIR) ++ #cp xv_mgcsfx.sample $(DESTDIR)$(SYSCONFDIR)/xv_mgcsfx + + tar: + # tar only local jpeg and tiff dirs, not user's or system's copies: +@@ -299,7 +385,7 @@ + xvbrowse.o: bits/br_pcx bits/br_jfif bits/br_tiff bits/br_pds + xvbrowse.o: bits/br_ps bits/br_iff bits/br_targa bits/br_xpm + xvbrowse.o: bits/br_trash bits/fcurs bits/fccurs bits/fdcurs bits/fcursm +-xvbrowse.o: bits/br_xwd ++xvbrowse.o: bits/br_xwd bits/br_png bits/br_zx bits/br_pcd bits/br_bzip2 + + xvbutt.o: bits/cboard50 bits/rb_frame bits/rb_frame1 bits/rb_top + xvbutt.o: bits/rb_bot bits/rb_dtop bits/rb_dbot bits/rb_body +diff -ruN xv-3.10a-bugfixes/Makefile.std xv-3.10a-enhancements/Makefile.std +--- xv-3.10a-bugfixes/Makefile.std 2005-04-06 08:17:13.000000000 -0700 ++++ xv-3.10a-enhancements/Makefile.std 2005-05-01 10:23:32.000000000 -0700 +@@ -41,10 +41,14 @@ + + + ### Installation locations +-BINDIR = /usr/local/bin +-MANDIR = /usr/local/man/man1 ++PREFIX = /usr/local ++BINDIR = $(PREFIX)/bin ++MANDIR = $(PREFIX)/man/man1 + MANSUF = 1 +-LIBDIR = /usr/local/lib ++DOCDIR = $(PREFIX)/doc/xv-3.10a ++LIBDIR = $(PREFIX)/lib/xv ++SYSCONFDIR = $(PREFIX)/etc ++DESTDIR = + + + buildit: all +@@ -59,13 +63,59 @@ + ### on your machine, *COMMENT OUT* the following lines + ### + JPEG = -DDOJPEG +-JPEGDIR = jpeg +-JPEGINC = -I$(JPEGDIR) +-JPEGLIB = $(JPEGDIR)/libjpeg.a +-$(JPEGDIR)/jconfig.h: +- cd $(JPEGDIR) ; ./configure CC='$(CC)' +-$(JPEGLIB): $(JPEGDIR)/jconfig.h +- cd $(JPEGDIR) ; make ++#JPEGDIR = jpeg ++JPEGDIR = /usr ++#JPEGDIR = /usr/local ++#JPEGDIR = ../../libjpeg ++### ++JPEGINC = -I$(JPEGDIR)/include ++#JPEGINC = -I$(JPEGDIR) ++### ++JPEGLIB = -L$(JPEGDIR)/lib -ljpeg ++#JPEGLIB = -L$(JPEGDIR) -ljpeg ++#JPEGLIB = $(JPEGDIR)/libjpeg.a ++### ++### this is intended to build the ancient version (5a) that's included in the ++### "jpeg" subdir of XV, not an arbitrary copy of libjpeg: ++### ++#$(JPEGDIR)/jconfig.h: ++# cd $(JPEGDIR) ; ./configure CC='$(CC)' ++#$(JPEGLIB): $(JPEGDIR)/jconfig.h ++# cd $(JPEGDIR) ; make ++ ++ ++### ++### if, for whatever reason, you're unable to get the PNG library to compile ++### on your machine, *COMMENT OUT* the following lines ++### ++PNG = -DDOPNG ++PNGDIR = /usr ++#PNGDIR = /usr/local ++#PNGDIR = ../../libpng ++### ++PNGINC = -I$(PNGDIR)/include ++#PNGINC = -I$(PNGDIR) ++### ++PNGLIB = -L$(PNGDIR)/lib -lpng ++#PNGLIB = -L$(PNGDIR) -lpng ++#PNGLIB = $(PNGDIR)/libpng.a ++ ++ ++### ++### if, for whatever reason, you're unable to get both the PNG library and ++### (newer versions of) the TIFF library to compile on your machine, *COMMENT ++### OUT* the following lines ++### ++ZLIBDIR = /usr ++#ZLIBDIR = /usr/local ++#ZLIBDIR = ../../zlib ++### ++ZLIBINC = -I$(ZLIBDIR)/include ++#ZLIBINC = -I$(ZLIBDIR) ++### ++ZLIBLIB = -L$(ZLIBDIR)/lib -lz ++#ZLIBLIB = -L$(ZLIBDIR) -lz ++#ZLIBLIB = $(ZLIBDIR)/libz.a + + + ### +@@ -80,17 +130,32 @@ + ### + #TIFF = -DDOTIFF + TIFF = -DDOTIFF -DUSE_TILED_TIFF_BOTLEFT_FIX +-TIFFDIR = tiff +-TIFFINC = -I$(TIFFDIR) +-TIFFLIB = $(TIFFDIR)/libtiff.a +-$(TIFFLIB): +- ( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' ) ++#TIFFDIR = tiff ++TIFFDIR = /usr ++#TIFFDIR = /usr/local ++#TIFFDIR = ../../libtiff ++### ++TIFFINC = -I$(TIFFDIR)/include ++#TIFFINC = -I$(TIFFDIR) ++### ++### libtiff 3.5 and up may be compiled with zlib and libjpeg, but dependency ++### is properly handled in LIBS line ~143 lines below ++### ++TIFFLIB = -L$(TIFFDIR)/lib -ltiff ++#TIFFLIB = -L$(TIFFDIR) -ltiff ++#TIFFLIB = $(TIFFDIR)/libtiff.a ++### ++### this is intended to build the ancient version (3.3.016 beta) that's included ++### in the "tiff" subdir of XV, not an arbitrary copy of libtiff: ++### ++#$(TIFFLIB): ++# ( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' ) + + + ### + ### if, for whatever reason, you're unable to get the PDS/VICAR support + ### to compile (xvpds.c, and vdcomp.c), *COMMENT OUT* the following line, +-### and also remove 'vdcomp' from the 'all:' dependancy ++### and also remove 'vdcomp' from the 'all:' dependency + ### + PDS = -DDOPDS + +@@ -98,8 +163,10 @@ + #----------System V---------- + + # if you are running on a SysV-based machine, such as HP, Silicon Graphics, +-# Solaris, etc., uncomment the following line to get mostly there. +-#UNIX = -DSVR4 ++# Solaris, etc.; uncomment one of the following lines to get you *most* of ++# the way there. SYSV means System V R3. ++# UNIX = -DSVR4 ++# UNIX = -DSYSV + + + #----------Machine-Specific Configurations---------- +@@ -121,12 +188,15 @@ + # To use old HP compilers (HPUX 7.0 or so), you may need + #MCHN= -Dhpux -D_HPUX_SOURCE +Ns4000 + # +-# also, if you're using HP's compiler, add '-Aa' to whichever of those ++# Also, if you're using HP's compiler, add '-Aa' to whichever of those + # two lines you're using, to turn on ANSI C mode. Or so I'm told. + # +-# note: You may need to add '-I/usr/include/X11R5' (or R6, or whatever) ++# Note: You may need to add '-I/usr/include/X11R5' (or R6, or whatever) + # to whichever of those lines you used, as HP tends to store their X11 + # include files in a non-standard place... ++# ++# And you probably have to add '-lV3' to the end of the LIBS def when ++# using XV's AUTO_EXPAND option. + + + ### for LINUX, uncomment the following line +@@ -205,6 +275,16 @@ + #VPRINTF = -DNEED_VPRINTF -DLONGINT -DNOSTDHDRS + + ++# if your X Window System compiled with -DX_LOCALE, ++# uncomment the following line: ++# TVL10N = -DX_LOCALE ++ ++# Install directory of xv_mgcsfx.sample. ++MGCSFXDIR = $(LIBDIR) ++# Directory of default configuration file. ++MGCSFX = -DMGCSFXDIR=\"$(MGCSFXDIR)\" ++ ++ + + + ################ END OF CONFIGURATION OPTIONS ################# +@@ -212,13 +292,14 @@ + + + +-CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \ +- $(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \ +- $(DXWM) $(MCHN) ++CFLAGS = $(CCOPTS) $(PNG) $(PNGINC) $(ZLIBINC) $(JPEG) $(JPEGINC) \ ++ $(TIFF) $(TIFFINC) $(PDS) $(NODIRENT) $(VPRINTF) $(TIMERS) \ ++ $(UNIX) $(BSDTYPES) $(RAND) $(DXWM) $(MCHN) $(TVL10N) $(MGCSFX) \ ++ -DSYSCONFDIR=\"$(SYSCONFDIR)\" -DXVEXECPATH=\"$(LIBDIR)\" + + ### remove -lm for BeOS: +-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm +-#LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) ++LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -L/usr/X11R6/lib -lX11 -lm ++#LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -lX11 + + OBJS = xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \ + xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \ +@@ -226,7 +307,9 @@ + xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \ + xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \ + xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \ +- xvxwd.o xvfits.o ++ xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o xvhips.o \ ++ xvmag.o xvpic.o xvmaki.o xvpi.o xvpic2.o xvvd.o xvmgcsfx.o \ ++ xvml.o + + MISC = README INSTALL CHANGELOG IDEAS + +@@ -236,10 +319,12 @@ + + + +-all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm ++#all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm ++all: xv bggen vdcomp xcmap xvpictoppm + + +-xv: $(OBJS) $(JPEGLIB) $(TIFFLIB) ++#xv: $(OBJS) $(JPEGLIB) $(TIFFLIB) ++xv: $(OBJS) + $(CC) -o xv $(CFLAGS) $(OBJS) $(LIBS) + + bggen: bggen.c +@@ -268,13 +353,14 @@ + + + install: all +- cp xv bggen vdcomp xcmap xvpictoppm $(BINDIR) +- cp docs/xv.man $(MANDIR)/xv.$(MANSUF) +- cp docs/bggen.man $(MANDIR)/bggen.$(MANSUF) +- cp docs/xcmap.man $(MANDIR)/xcmap.$(MANSUF) +- cp docs/xvp2p.man $(MANDIR)/xvpictoppm.$(MANSUF) +- cp docs/vdcomp.man $(MANDIR)/vdcomp.$(MANSUF) +- cp docs/xvdocs.ps* $(LIBDIR) ++ cp xv bggen vdcomp xcmap xvpictoppm $(DESTDIR)$(BINDIR) ++ cp docs/xv.man $(DESTDIR)$(MANDIR)/xv.$(MANSUF) ++ cp docs/bggen.man $(DESTDIR)$(MANDIR)/bggen.$(MANSUF) ++ cp docs/xcmap.man $(DESTDIR)$(MANDIR)/xcmap.$(MANSUF) ++ cp docs/xvp2p.man $(DESTDIR)$(MANDIR)/xvpictoppm.$(MANSUF) ++ cp docs/vdcomp.man $(DESTDIR)$(MANDIR)/vdcomp.$(MANSUF) ++ cp docs/xvdocs.ps* $(DESTDIR)$(LIBDIR) # or $(DESTDIR)$(DOCDIR) ++ #cp xv_mgcsfx.sample $(DESTDIR)$(SYSCONFDIR)/xv_mgcsfx + + tar: + # tar only local jpeg and tiff dirs, not user's or system's copies: +@@ -299,7 +385,7 @@ + xvbrowse.o: bits/br_pcx bits/br_jfif bits/br_tiff bits/br_pds + xvbrowse.o: bits/br_ps bits/br_iff bits/br_targa bits/br_xpm + xvbrowse.o: bits/br_trash bits/fcurs bits/fccurs bits/fdcurs bits/fcursm +-xvbrowse.o: bits/br_xwd ++xvbrowse.o: bits/br_xwd bits/br_png bits/br_zx bits/br_pcd bits/br_bzip2 + + xvbutt.o: bits/cboard50 bits/rb_frame bits/rb_frame1 bits/rb_top + xvbutt.o: bits/rb_bot bits/rb_dtop bits/rb_dbot bits/rb_body +diff -ruN xv-3.10a-bugfixes/README.jumbo xv-3.10a-enhancements/README.jumbo +--- xv-3.10a-bugfixes/README.jumbo 2005-04-10 19:55:23.000000000 -0700 ++++ xv-3.10a-enhancements/README.jumbo 2005-05-01 13:45:58.000000000 -0700 +@@ -14,10 +14,10 @@ + available from John's XV site (http://www.trilon.com/xv/downloads.html + and ftp://ftp.trilon.com/pub/xv/patches/), plus a number of my own fixes + and additions, plus quite a few from other people--though not all of the +-ones I'd intended to (sorry, SJT, AT, and JPD!) due to lack of time after +-dealing with the latest security issue (which I discovered, sigh). They're +-still not fully complete, and it's possible they never will be, but I do +-plan to continue working on them whenever the mood strikes--and I may even ++ones I'd intended to, due to lack of time after dealing with the latest ++set of security issues (one of which I discovered, sigh). They're still ++not fully complete, and it's possible they never will be, but I do plan ++to continue tinkering with them whenever the mood strikes--and I may even + release them publicly on rare occasions. (At the current rate, it looks + like once a year may be the best we can hope for...we'll see.) + +@@ -26,91 +26,86 @@ + + - Landon Curt "chongo" Noll (http://www.isthe.com/chongo/) + http://www.isthe.com/chongo/src/xv-patch/ +- - Mark Ashley <mark@ibiblio.org> ++ - Mark Ashley <mark ibiblio.org> + http://www.ibiblio.org/pub/packages/solaris/sparc/html/xv.3.10a.p19.html +- - Peter Jordan <pete@dc.seflin.org> ++ - Peter Jordan <pete dc.seflin.org> + http://www.ibiblio.org/pub/Linux/apps/graphics/viewers/X/xv-3.10a.patch.* + - Uwe F. Mayer (http://www.tux.org/~mayer/) + http://www.tux.org/~mayer/linux/book/node311.html +- - Kurt Wall <kwall@kurtwerks.com> ++ - Kurt Wall <kwall kurtwerks.com> + http://www.kurtwerks.com/software/xv.html + - Chisato Yamauchi (http://phe.phyas.aichi-edu.ac.jp/~cyamauch/index_en.html) + http://phe.phyas.aichi-edu.ac.jp/~cyamauch/xv.html +- - Daisuke Yabuki <dxy@optix.org> ++ - Daisuke Yabuki <dxy optix.org> + http://www.optix.org/~dxy/solaris/xv/ + - Pekoe (http://pekoe.lair.net/) + http://pekoe.lair.net/diary/xv.html + - FreeBSD FreshPorts + http://www.freshports.org/graphics/xv/ +- - <sudakyo@fat.coara.or.jp> ++ - Kyoichiro Suda <sudakyo fat.coara.or.jp> + http://www.coara.or.jp/~sudakyo/XV_jp.html + +-I very much doubt that this is an exhaustive list. So far, most of the other +-patch-sets appear not to be quite as extensive or as up-to-date as my own, +-although the last three or four do include the [large] Japanese extension +-patches that I omitted--not because they're unworthy, but simply because I +-didn't find them until collisions between the two sets of patches had become +-a large problem. (Maybe for the next release... I'd intended to try for +-this release, but the security issues ended up taking almost all of my +-available time. And, to be honest, from my perspective, inclusion of the +-jp-extension patches is more for completeness' sake than personal interest, +-so their priority is fairly low.) ++I very much doubt that this is an exhaustive list. So far, most of the ++other patch-sets appear not to be as extensive or as up-to-date as my own, ++particularly now that the (very large) "Japanese extension" patches are ++incorporated--big thanks to Werner Fink of SuSE for that! + + Below I summarize the component patches that are encompassed by my jumbo + bugfixes and jumbo enhancements patches. Unfortunately, some of my own + additions never saw the light of day as standalone patches, but considering + the number of overlaps (collisions) already implicit in this list, it would +-have been difficult to accomplish even if I'd had the time. In any case, +-they're present in these jumbo patches but not chongo's, so those who _really_ +-care can "subtract" the two sets of patches to see what I did. ++have been difficult to accomplish even if I'd had the time. + + Here's a quick guide to the "third-party" credits in the lists below: + + AAC = Andrey A. Chernov [ache] + (http://cvsweb.freebsd.org/ports/graphics/xv/files/patch-ab) +- AD = Andreas Dilger (adilger@clusterfs.com) +- AL = Alexander Lehmann (lehmann@usa.net) ++ AD = Andreas Dilger (adilger clusterfs.com) ++ AL = Alexander Lehmann (lehmann usa.net) + AT = Anthony Thyssen (http://www.cit.gu.edu.au/~anthony/) + DAC = David A. Clunie (http://www.dclunie.com/xv-pcd.html) +- EK = Egmont Koblinger (egmont@users.sourceforge.net) ++ EK = Egmont Koblinger (egmont users.sourceforge.net) + GRR = Greg Roelofs (http://pobox.com/~newt/) + GV = Guido Vollbeding (http://sylvana.net/guido/) ++ IM = IKEMOTO Masahiro (ikeyan airlab.cs.ritsumei.ac.jp) + JCE = John C. Elliott (http://www.seasip.demon.co.uk/ZX/zxdload.html) + JHB = John H. Bradley, of course (http://www.trilon.com/xv/) + JPD = Jean-Pierre Demailly (http://www-fourier.ujf-grenoble.fr/~demailly/) + JR = John Rochester (http://www.freebsd.org/cgi/query-pr.cgi?pr=2920) + (also http://cvsweb.freebsd.org/ports/graphics/xv/files/patch-af, -ag) + JZ = Joe Zbiciak (http://spatula-city.org/~im14u2c/) ++ KS = Kyoichiro Suda (http://www.coara.or.jp/~sudakyo/XV_jp.html) + LCN = Landon Curt "chongo" Noll (http://www.isthe.com/chongo/) ++ LJ = Larry Jones (lawrence.jones ugs.com) + PBJ = Peter Jordan (http://www.ibiblio.org/pub/Linux/apps/graphics/viewers/X/) + PSV = Pawel S. Veselov (http://manticore.2y.net/wbmp.html) + SB = Sean Borman (http://www.nd.edu/~sborman/software/xvwheelmouse.html) +- SJT = TenThumbs (tenthumbs@cybernex.net) ++ SJT = TenThumbs (tenthumbs cybernex.net) + TA = Tim Adye (http://hepwww.rl.ac.uk/Adye/xv-psnewstyle.html) ++ TI = Tetsuya INOUE (tin329 chino.it.okayama-u.ac.jp) ++ TO = Tavis Ormandy (taviso gentoo.org) ++ WF = Werner Fink (http://www.suse.de/~werner/) + + Other credits are as listed on the XV Downloads page or in the respective + patches (e.g., the jp-extension patches or within the PNG patch). + + Finally, please note that these patches have not been blessed by John Bradley +-in any way (although I copied him on the May 2004 announcement--no response). +-Nor have I personally tested every change and feature! (See the BIG SCARY +-WARNING below for further caveats.) In other words, they're both completely +-unofficial and completely unguaranteed. But they seem to work for me. (And +-when they don't, I fix 'em. Eventually, anyway... ;-) ) +- +-One further "final" note: this may well be the last release to include +-separate fix- and enhancements-patches. It is too much of a timesink to +-maintain parallel trees--not to mention parallel makefiles (generic/public +-vs. local/personal, old vs. new libjpeg/libtiff) and xv.h (unregistered/ +-public vs. registered/personal), particularly when some fixes come about +-while working on an enhancement. Henceforth--assuming, of course, that +-there _is_ a "henceforth"--I expect to merge the patches into a single +-jumbo patch. (Alternatively, I may simply freeze the current fix-patch +-and continue to evolve only the enhancements patch; in particular, new +-fixes would appear only in it. Either approach would be simple enough; +-feedback as to which would be preferable is welcomed.) ++in any way (although I copied him on the May 2004 announcement--no response ++at that time). Nor have I personally tested every change and feature! (See ++the BIG SCARY WARNING below for further caveats.) In other words, they're ++both completely unofficial and completely unguaranteed. But they seem to ++work for me. (And when they don't, I fix 'em. Eventually, anyway... ;-) ) ++ ++One further "final" note: as of this release, I am no longer updating the ++fixes patch; new stuff (including fixes) now appears only in the enhancements ++one. It simply became too much of a timesink to maintain parallel trees--not ++to mention parallel makefiles (generic/public vs. local/personal, old vs. ++new libjpeg/libtiff) and xv.h (unregistered/public vs. registered/personal), ++particularly when some fixes came about while working on an enhancement and ++others were provided by third parties relative to the previous fix+enh state. ++Hence the mismatched "20050410" date on the fixes patch. + +-GRR 20050410 ++GRR 20050501 + + + How to build +@@ -158,8 +153,8 @@ + Assuming you have the prerequisites out of the way and aren't scared + off by the Big Scary Warning, here's the build procedure: + +- bzip2 -dc xv-3.10a-jumbo-patches-20050410.tar.bz2 | tar xvf - +- (or tar xvzf xv-3.10a-jumbo-patches-20050410.tar.gz) ++ bzip2 -dc xv-3.10a-jumbo-patches-20050501.tar.bz2 | tar xvf - ++ (or tar xvzf xv-3.10a-jumbo-patches-20050501.tar.gz) + + tar xvzf xv-3.10a.tar.gz + +@@ -167,7 +162,7 @@ + + patch -p1 < ../xv-3.10a-jumbo-fix-patch-20050410.txt + +- [optional] patch -p1 < ../xv-3.10a-jumbo-enh-patch-20050410.txt ++ [optional] patch -p1 < ../xv-3.10a-jumbo-enh-patch-20050501.txt + + edit Makefile and config.h as directed in INSTALL file (in particular, + ensure paths to external libraries and header files are correct) +@@ -221,6 +216,8 @@ + - freebsd-vdcomp-newline.patch (AAC) + - xv-3.10a.patch.linux (PBJ) [/bin/sh versions of cleandir, RANLIB.sh only] + - removed trailing white space (GRR) [purely cosmetic] ++20040523: ++ - fixed compilation error in registered versions (GRR) + 20050410: + - fix for YCbCr oversaturated-green bug(s) in TIFF decoder (GRR) + - provisional fix for contiguous tiled TIFFs with bottom-* orientation (GRR) +@@ -265,12 +262,50 @@ + - boosted maximum number of files from 4096 to 32768 (GRR) + (note that OS kernel limits may also apply; for example, in Linux see + MAX_ARG_PAGES in linux-<version>/include/linux/binfmts.h) +- - xv-3.10a-bmp16.patch +- (from http://www.coara.or.jp/~sudakyo/XV_jp.html) ++ - xv-3.10a-bmp16.patch (KS) + - final-image delay (e.g., "-wait 0.2,3" : pause 3 secs on final image) (GRR) + - xv-numpad.patch (EK) + - xv-delete-is-not-backspace.patch (EK) + - made browser window (schnauzer) and icons configurable (AT, GRR) ++20050501: ++ - xv-3.10a-bmpfix.patch (WF) [*SECURITY*] ++ - xv310a-jp-extension-rev5.3.3.tar.gz (TI, IM, ..., WF) ++ (adds support for MAG, MAKI, Pi, PIC, and PIC2 formats[*]; "magic suffix" ++ detection/conversion; MacBinary prefixes; archives as virtual filesystems; ++ multilingual text viewer [though not Unicode]; etc.) ++ - xv-3.10a-yaos.dif (WF, TO) [*SECURITY*] ++ (fixes a number of format-string issues and system() calls) ++ - xv-3.10a.dif (WF) [*SECURITY*] ++ (fixes more format-string issues, mktemp() and open() calls, and compilation ++ warnings [mostly from jp-extension patch]) ++ - xv-3.10a-jumbo-jpd_startgrab-patch-20050420.txt (JPD) ++ - PATCH.alwaysnever (LJ) ++ - PATCH.bsd (LJ) ++ - PATCH.linedraw (LJ) ++ - PATCH.multipage (LJ) ++ - PATCH.multipageGIF (LJ) ++ - PATCH.random (LJ) ++ - PATCH.stat (LJ) ++ - PATCH.thumbs (LJ) ++ - xv-startgrab-imake-hips.patch (JPD) ++ ("hips" portion only; adds support for HIPS image format[*]) ++ - xv-3.10a-formatstr.patch (KS) ++ - xv-3.10a-shortsleep.patch (KS) ++ - xv-3.10a-locale-linux.patch (KS) ++ - xv-3.10a-printkey.patch (KS) ++ - xv-3.10a-sysconfdir.patch (KS) ++ - added PREFIX and DESTDIR support to Makefile (KS, GRR) ++ - xv-3.10a-xvexecpath.patch (but disabled pending fixes) (KS) ++ - xv-3.10a-zeroquit.patch (KS, GRR) ++ ++ ++[*] Note that all six of these formats may still suffer from exploitable heap ++ overflows [*SECURITY*] when decoding images with large (possibly invalid) ++ dimensions; as a result, they are DISABLED by default. (Search for "GRR ++ POSSIBLE OVERFLOW / FIXME" comments in xvmag.c, xvmaki.c, xvpi.c, xvpic.c, ++ xvpic2.c, and xvhips.c, but keep in mind that these may not be exhaustive.) ++ Users who choose to overlook these security issues can enable any or all ++ of them by editing config.h. + + + not (yet?) included: +@@ -284,31 +319,21 @@ + -rw-r--r-- 42397 Mar 11 2004 xv-3.10a-download-test2.patch + -rw-r--r-- 47679 Mar 11 2004 xv-3.10a-download-test3.patch + -rw-r--r-- 52745 Mar 11 2004 xv-3.10a-download-test4.patch +- -rw-r--r-- 415 Mar 11 2004 xv-3.10a-formatstr.patch + -rw-r--r-- 3423 Apr 24 2004 xv-3.10a-keyzoom.patch +- -rw-r--r-- 1461 Mar 11 2004 xv-3.10a-locale-linux.patch + -rw-r--r-- 12387 Mar 15 2004 xv-3.10a-menubutton.patch + -rw-r--r-- 1178 Apr 24 2004 xv-3.10a-noblink.patch +- -rw-r--r-- 484 Mar 11 2004 xv-3.10a-printkey.patch + -rw-r--r-- 57092 Jul 9 2004 xv-3.10a-resolution.patch + -rw-r--r-- 4645 Apr 24 2004 xv-3.10a-selall.patch +- -rw-r--r-- 360 Mar 11 2004 xv-3.10a-shortsleep.patch + -rw-r--r-- 702 Apr 24 2004 xv-3.10a-showlongname.patch + -rw-r--r-- 1205 Apr 24 2004 xv-3.10a-staytoppdir.patch +- -rw-r--r-- 1591 Mar 15 2004 xv-3.10a-sysconfdir.patch + -rw-r--r-- 4228 Apr 24 2004 xv-3.10a-wheelmouse.patch + -rw-r--r-- 744 Apr 24 2004 xv-3.10a-xvbutt_wait.patch +- -rw-r--r-- 712 Mar 11 2004 xv-3.10a-xvexecpath.patch + -rw-r--r-- 3757 Jul 9 2004 xv-3.10a-xvscrl_button2.patch + -rw-r--r-- 1494 Jul 9 2004 xv-3.10a-xvscrl_wait.patch + -rw-r--r-- 19352 Jul 9 2004 xv-3.10a-xvzoom.patch +- -rw-r--r-- 1827 Apr 24 2004 xv-3.10a-zeroquit.patch + +- - xv310a-jp-extension-rev5.3.3.tar.gz [extensive] +- - xv-3.10a-jp-extension-5.3.3-png-1.2d.patch [PNG patch relative to jp-ext] +- - xv-3.10a+jp-extension-rev5.3.3+FLmask.v2.1+png+misc.patch [??] ++ - xv-3.10a+jp-extension-rev5.3.3+FLmask.v2.1+png+misc.patch ["mask" support] + +- - xv-grab-imake-hips.patch (JPD) [HIPS format, -startgrab option] + - xv-psnewstyle.patch (TA) [coming later in 2005?] + - xv-3.10a.patch.linux (PBJ) [maybe use vdcomp.c changes?] + - xvxpm-anthony-thyssen.c (AT) ["slate grey" bug already gone?] +@@ -332,8 +357,8 @@ + not finished (and/or even started ;-) ): + + - fix xvpng.c not to use direct struct access +- - fix for never-ending pile of SLOW popups when viewing TIFFs with unknown tags +- (or truncated/corrupted images) ++ - (better) fix for never-ending pile of SLOW popups when viewing TIFFs with ++ unknown tags (or truncated/corrupted images) + - fix for minor .Z inefficiency in xv.c ("FIXME") + - fix for filename entry-field mouse/cursor bogosity + (want at least positioning to work; preferably also select/cut/paste) +@@ -344,6 +369,7 @@ + - transparency support for TIFF, XPM and TGA images + - support for tiled background image (with transparent foreground image) + - MNG/JNG support ++ - SVG support + + + ChangeLog +@@ -364,7 +390,7 @@ + 20040531 + fixed undefined CLK_TCK with gcc -ansi (enh/USE_TICKS option); made + libjpeg, libtiff, libpng and zlib sections of makefile more consistent +- (enh); ++ (enh) + + 20040606 + added freshmeat link, build instructions, and changelog to jumbo README +@@ -385,3 +411,32 @@ + sex bug in 24-bit FixPix display code (enh/USE_24BIT_ENDIAN_FIX option); + fixed numerical-keypad NumLock behavior and delete-key behavior in file- + load/save window (enh); made schnauzer window and icons configurable (enh) ++ ++ 20050417 ++ incorporated "Japanese extension" patches, revision 5.3.3 (enh); fixed ++ additional *SECURITY* issues (format-string vulnerabilities, system() ++ and mktemp() calls, etc., but NOT heap overflows in new decoders) both ++ in existing code and in jp-extension additions (enh) ++ ++ 20050425 ++ added support for -startgrab option (enh); added support for a "Never" ++ button to file-overwrite popups (enh); added NetBSD and BSDI to list of ++ mkstemp()-supporting systems (enh); improved line-drawing code to set the ++ correct pixels for lines of all slopes (enh); added "Page n of m" to Info ++ window for multipage images (enh); added support for multipage (animated) ++ GIFs (enh); fixed -random support so randomized file list can be traversed ++ normally in forward or backward direction (enh); added typecasts to stat() ++ printfs for portability (enh); fixed erroneous use of "creation" time and ++ forced unlink prior to overwrite in schnauzer thumbnail code (enh); added ++ HIPS support (enh/HAVE_HIPS option) ++ ++ 20050501 ++ extended multipage keyboard support (PgUp/PgDn) to all windows except ++ control ("console") and directory (enh); fixed minor (non-security) ++ format-string issue in xv.c (enh); shortened delay on popup error windows ++ from 3 seconds to 1 second (enh); tweaked text-viewer localization support ++ (TV_L10N) for Linux (enh); added keyboard short cuts for Color and ++ Grayscale buttons in print dialog (enh); added support for separate "magic ++ suffix" (xv_mgcsfx) config dir (enh); added PREFIX and DESTDIR support to ++ Makefile (enh); fixed handling of zero-length files and other text-viewer ++ failures (enh) +diff -ruN xv-3.10a-bugfixes/README.pcd xv-3.10a-enhancements/README.pcd +--- xv-3.10a-bugfixes/README.pcd 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/README.pcd 2001-07-08 11:21:19.000000000 -0700 +@@ -0,0 +1,159 @@ ++Copyright 1993-2001 David Clunie. ++ ++PCD patch for XV 3.10a Release Notes 2001/07/08. ++ ++See also the progress notes at the end of this file. Thanks to all those ++contributors who have substantially improved this patch. ++ ++These patches allow xv to read Kodak photocd files and choose which of the ++5 available resolutions one wants to view. ++ ++When a photocd file is loaded, a dialog box asks which resolution you ++would like. The visual schnauzer builds thumbnails by reading the lowest ++resolution image. The selected resolution can be selected from the ++command line with the -pcd option: ++ ++ [-pcd 0|1|2|3|4] ++ ++where: ++ ++ 0=192*128, base/16 resolution ++ 1=384*256, base/4 resolution ++ 2=768*512, base resolution ++ 3=1536*1024, 4base resolution ++ 4=3072*2048 16base resolution. ++ ++Note that the Pro format is not supported. ++ ++The command line option allows loops without the dialog box popping up, eg.: ++ ++ xv -pcd 1 -wloop -wait 10 *.pcd ++ ++The code is pretty crude and was written quickly for a specific purpose and ++has not really been cleaned up. It is poorly structured, full of debugging ++codes and verbose comments, and there is very little attempt at optimizing ++things. No profiling has been done. ++ ++There is not yet support for overview files, nor is there a facility to ++use the higher resolution chroma planes from when viewing lower resolution ++images. ++ ++It's only claim to fame is that it works and produces reasonable looking ++images. ++ ++The outline of this is shamelessly derived from xvpbm.c to read the ++file, and xvtiffwr.c to handle the popup window and X stuff (X never ++has been my forte !), and the PhotoCD format information (though not ++the code) was found in Hadmut Danisch's (danisch@ira.uka.de) hpcdtoppm ++program in which he has reverse engineered the format by studying ++hex dumps of PhotoCDs ! The color stuff and Huffman decding were ++extensively revised by Matthew Francey. ++ ++Feel free to send me comments or improvements, or even better, more ++information about the photo CD format ... hopefully someone who really ++knows what they are doing will tidy it up or do a neater job. ++ ++david (dclunie@dclunie.com) ++ ++--------- ++ ++The trace #define in xvpcd.c is now in the right place, and the ansi ++prototype for the magnify function has been fixed. Colin made me switch to ++xvbcopy() which seems like a good idea for System V victims. ++ ++--------- ++ ++Date: Wed, 22 Dec 1993 16:09:52 --1000 ++From: colinc@fitmail.fit.qut.edu.au (Colin Canfield ) ++ ++I have done some more work using your patch I thought you might be intested in. ++The major change was adding a size parameter to the LoadPCD; either -1 to mean ++the popup or else the size you desired. This allows batch mode processing, ++specifically xv -pcd <size> <filename>, and the visual schnauzer can work in ++quick mode (ie. you don't have to select each image size when it is building ++the icons) ++ ++I have added an xbm file for the file type but haven't drawn an icon for it, ++this is in bitmaps/br_pcd.xbm. I will just send you the new files. ++ ++--------- ++ ++From: andrew@andrew.triumf.ca (Andrew Daviel) ++Date: 16 Feb 1995 23:32:21 GMT ++ ++This is David Clunie's patch for xv-3.00 tuned a bit to work ++on xv-3.10. The code's all the same except for replacing ++"trace" with "fprintf" in xvpcd.c and adding an "unsigned" qualifier to ++keep my compiler (gcc) happy. Oh yes, changed RFT_PCD to 20 as ++John Bradley has now used 15 through 19. ++ ++--------- ++ ++From: dclunie@flash.us.com (David A. Clunie) ++Date: Thu Jun 15 14:43:46 GMT+0300 1995 ++ ++Andrew's patch didn't include Colin's browser changes, so I redid the ++xv-3.10 update from scratch ... it seems pretty much the same as ++Andrew's changes. I also edited the Imakefile and Makefiles in order ++to support the PCD changes, as well as make the install process a ++little more flexible, with options to strip and set modes and so on. ++Also made RFT_PCD 25 so as not to conflict with magpic patch from Japan ++by Ikemoto Masahiro <ikeyan@airlab.cs.ritsumei.ac.jp>, and used his ++bitmap icon for pcd files. ++ ++Now there are two versions of the patch, one which should be applied ++to the xv-3.10 distribution. ++ ++The other should be applied to xv-3.10 AFTER Ikemoto Masahiro's ++Patch.magpic2.PhotoCD.XV319a, in order to add the browser features to ++the latter, as well as fixing a Makefile typo (was xcpcd.c not xvpcd.c) ++and including unistd.h for the SEEK_xxx constants in the magicpic ++stuff. ++ ++--------- ++ ++Subject: Re: photo-cd patch for xv ++From: Matthew Francey <mdf@angoss.com> ++Date: Mon, 26 Mar 2001 15:37:55 +0000 ++ ++Attached is a revised version of xvpcd.c; the areas that I have ++re-written or changed are in a different coding style so you can tell ++what has changed. The GNU 'indent' program can be run against the file ++to enforce a consistent style .. ++ ++Here is what I've done though: ++ ++a) huffman table reader re-written, because it would fail on some ++ photocd files with "unusual" huffman codes. ++ ++b) the huffman-coded corrections are now properly applied ++ ++c) the corrections can sometimes over or underflow; clipping has been ++ introduced and effectively fixes the problem, but I suspect that ++ there is something deeper going on. ++ ++d) the "official" YCC->sRGB transform is done. a "beyond 100% white" ++ mapping table was snarfed from ImageMagick. an option for using a ++ flat linear LUT was added -- this can make somewhat over-exposed images ++ look alot nicer. ++ ++e) there were strange problems where the code wouldn't be able to find ++ the huffman tables and data for the 16base image (the bit-buffering ++ code was starting mid-sector, instead of at a sector boundary). Looking ++ at a pcd file with a hex editor suggests to me that it is possible to ++ just skip directly to these huffman tables -- no special "+12" and such ++ constants necessary. But I haven't tried this yet. ++ ++The results: I've been able to read about 50 or 60 .pcd files [scattered ++in age from 6 years old to scans done last week] with this code without ++incident. Image quality at the high resolution is excellent. Even the ++trivial amount of LUT control is useful when dealing with over-exposed ++images. ++ ++If I get around to it: finer LUT control to take advantage of the ++slightly extended dynamic range of PhotoCD scans, especially in regards to ++dark or somewhat underexposed scenes. ++ ++ ++ ++ +diff -ruN xv-3.10a-bugfixes/bggen.c xv-3.10a-enhancements/bggen.c +--- xv-3.10a-bugfixes/bggen.c 2004-05-16 17:50:52.000000000 -0700 ++++ xv-3.10a-enhancements/bggen.c 2005-04-17 14:04:22.000000000 -0700 +@@ -34,7 +34,7 @@ + #define MAXCOLS 128 + + /* some VMS thing... */ +-#ifdef vax11c ++#if defined(vax11c) || (defined(__sony_news) && (defined(bsd43) || defined(__bsd43) || defined(SYSTYPE_BSD) || defined(__SYSTYPE_BSD))) + #include <ctype.h> + #endif + +diff -ruN xv-3.10a-bugfixes/bits/br_bzip2 xv-3.10a-enhancements/bits/br_bzip2 +--- xv-3.10a-bugfixes/bits/br_bzip2 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_bzip2 1998-04-12 19:23:39.000000000 -0700 +@@ -0,0 +1,27 @@ ++#define br_bzip2_width 48 ++#define br_bzip2_height 48 ++static unsigned char br_bzip2_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x7c, 0xbe, 0x3d, 0x0e, 0x02, 0x20, 0xfc, 0xbe, 0x7d, 0x1f, 0x02, ++ 0x20, 0xcc, 0xb0, 0x6d, 0x1b, 0x02, 0x20, 0xcc, 0x98, 0x6d, 0x1b, 0x02, ++ 0x20, 0xfc, 0x98, 0x6d, 0x18, 0x02, 0x20, 0x7c, 0x8c, 0x7d, 0x0c, 0x02, ++ 0x20, 0xcc, 0x8c, 0x3d, 0x0e, 0x02, 0x20, 0xcc, 0x84, 0x0d, 0x06, 0x02, ++ 0x20, 0xcc, 0x86, 0x0d, 0x03, 0x02, 0x20, 0xfc, 0xbe, 0x0d, 0x1f, 0x02, ++ 0x20, 0x7c, 0xbe, 0x0d, 0x1f, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03}; +diff -ruN xv-3.10a-bugfixes/bits/br_mag xv-3.10a-enhancements/bits/br_mag +--- xv-3.10a-bugfixes/bits/br_mag 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_mag 2005-04-17 14:04:22.000000000 -0700 +@@ -0,0 +1,27 @@ ++#define br_mag_width 48 ++#define br_mag_height 48 ++static unsigned char br_mag_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x0c, 0x86, 0xc1, 0x0f, 0x02, ++ 0x20, 0x0c, 0xc6, 0xe3, 0x1f, 0x02, 0x20, 0x1c, 0xe7, 0x67, 0x18, 0x02, ++ 0x20, 0x1c, 0x77, 0x6e, 0x18, 0x02, 0x20, 0xbc, 0x37, 0x6c, 0x00, 0x02, ++ 0x20, 0xbc, 0x37, 0x6c, 0x00, 0x02, 0x20, 0xec, 0x36, 0x6c, 0x1e, 0x02, ++ 0x20, 0xec, 0xf6, 0x6f, 0x1e, 0x02, 0x20, 0x4c, 0xf6, 0x6f, 0x18, 0x02, ++ 0x20, 0x4c, 0x36, 0x6c, 0x18, 0x02, 0x20, 0x0c, 0x36, 0x6c, 0x18, 0x02, ++ 0x20, 0x0c, 0x36, 0xec, 0x1f, 0x02, 0x20, 0x0c, 0x36, 0xcc, 0x0f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03}; +diff -ruN xv-3.10a-bugfixes/bits/br_maki xv-3.10a-enhancements/bits/br_maki +--- xv-3.10a-bugfixes/bits/br_maki 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_maki 2005-04-17 14:04:22.000000000 -0700 +@@ -0,0 +1,27 @@ ++#define br_maki_width 48 ++#define br_maki_height 48 ++static unsigned char br_maki_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x83, 0x61, 0x18, 0x33, 0x02, ++ 0x20, 0x83, 0xf1, 0x98, 0x33, 0x02, 0x20, 0xc7, 0xf9, 0x99, 0x31, 0x02, ++ 0x20, 0xc7, 0x9d, 0xdb, 0x30, 0x02, 0x20, 0xef, 0x0d, 0xfb, 0x30, 0x02, ++ 0x20, 0xef, 0x0d, 0x7b, 0x30, 0x02, 0x20, 0xbb, 0x0d, 0x7b, 0x30, 0x02, ++ 0x20, 0xbb, 0xfd, 0xdb, 0x30, 0x02, 0x20, 0x93, 0xfd, 0xdb, 0x30, 0x02, ++ 0x20, 0x93, 0x0d, 0x9b, 0x31, 0x02, 0x20, 0x83, 0x0d, 0x9b, 0x31, 0x02, ++ 0x20, 0x83, 0x0d, 0x1b, 0x33, 0x02, 0x20, 0x83, 0x0d, 0x1b, 0x33, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03}; +diff -ruN xv-3.10a-bugfixes/bits/br_mgcsfx xv-3.10a-enhancements/bits/br_mgcsfx +--- xv-3.10a-bugfixes/bits/br_mgcsfx 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_mgcsfx 2005-04-17 14:04:22.000000000 -0700 +@@ -0,0 +1,27 @@ ++#define br_mgcsfx_width 48 ++#define br_mgcsfx_height 48 ++static unsigned char br_mgcsfx_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x3c, 0xcf, 0x71, 0x00, 0x02, ++ 0x20, 0x6c, 0x61, 0xda, 0x00, 0x02, 0x20, 0x6c, 0x67, 0xd8, 0x1e, 0x02, ++ 0x20, 0x3c, 0x61, 0xd8, 0x1e, 0x02, 0x20, 0x6c, 0x61, 0xda, 0x00, 0x02, ++ 0x20, 0x6c, 0xcf, 0x71, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x4e, 0x7a, 0xef, 0x3d, 0x02, 0x20, 0xd3, 0x32, 0x68, 0x6c, 0x02, ++ 0x20, 0xc3, 0x32, 0xe4, 0x6c, 0x02, 0x20, 0x5b, 0x33, 0x62, 0x6c, 0x02, ++ 0x20, 0x53, 0x33, 0x61, 0x6c, 0x02, 0x20, 0x4e, 0x7a, 0xef, 0x3d, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03}; +diff -ruN xv-3.10a-bugfixes/bits/br_pcd xv-3.10a-enhancements/bits/br_pcd +--- xv-3.10a-bugfixes/bits/br_pcd 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_pcd 1995-06-15 21:31:53.000000000 -0700 +@@ -0,0 +1,27 @@ ++#define br_pcd_width 48 ++#define br_pcd_height 48 ++static unsigned char br_pcd_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x67, 0x00, 0xe0, 0x1c, 0x02, ++ 0x20, 0x6f, 0x00, 0xf0, 0x3d, 0x02, 0x20, 0x6b, 0x00, 0xb0, 0x2d, 0x02, ++ 0x20, 0x6b, 0x00, 0x33, 0x2c, 0x02, 0x20, 0x6b, 0x00, 0x33, 0x2c, 0x02, ++ 0x20, 0xeb, 0x98, 0x37, 0x2c, 0x02, 0x20, 0xef, 0xbd, 0x37, 0x2c, 0x02, ++ 0x20, 0x67, 0x2d, 0x33, 0x2c, 0x02, 0x20, 0x63, 0x2d, 0x33, 0x2c, 0x02, ++ 0x20, 0x63, 0x2d, 0x33, 0x2c, 0x02, 0x20, 0x63, 0x2d, 0xb3, 0x2d, 0x02, ++ 0x20, 0x63, 0x3d, 0xf7, 0x3d, 0x02, 0x20, 0x63, 0x19, 0xe6, 0x1c, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03}; +diff -ruN xv-3.10a-bugfixes/bits/br_pi xv-3.10a-enhancements/bits/br_pi +--- xv-3.10a-bugfixes/bits/br_pi 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_pi 2005-04-17 14:04:22.000000000 -0700 +@@ -0,0 +1,27 @@ ++#define br_pi_width 48 ++#define br_pi_height 48 ++static unsigned char br_pi_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x80, 0x1f, 0x7e, 0x00, 0x02, ++ 0x20, 0x80, 0x3f, 0x7e, 0x00, 0x02, 0x20, 0x80, 0x31, 0x18, 0x00, 0x02, ++ 0x20, 0x80, 0x31, 0x18, 0x00, 0x02, 0x20, 0x80, 0x31, 0x18, 0x00, 0x02, ++ 0x20, 0x80, 0x39, 0x18, 0x00, 0x02, 0x20, 0x80, 0x1f, 0x18, 0x00, 0x02, ++ 0x20, 0x80, 0x0f, 0x18, 0x00, 0x02, 0x20, 0x80, 0x01, 0x18, 0x00, 0x02, ++ 0x20, 0x80, 0x01, 0x18, 0x00, 0x02, 0x20, 0x80, 0x01, 0x18, 0x00, 0x02, ++ 0x20, 0x80, 0x01, 0x7e, 0x00, 0x02, 0x20, 0x80, 0x01, 0x7e, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03}; +diff -ruN xv-3.10a-bugfixes/bits/br_pic xv-3.10a-enhancements/bits/br_pic +--- xv-3.10a-bugfixes/bits/br_pic 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_pic 2005-04-17 14:04:22.000000000 -0700 +@@ -0,0 +1,27 @@ ++#define br_pic_width 48 ++#define br_pic_height 48 ++static unsigned char br_pic_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xf0, 0xf3, 0xf3, 0x01, 0x02, ++ 0x20, 0xf0, 0xf7, 0xfb, 0x03, 0x02, 0x20, 0x30, 0xc6, 0x18, 0x03, 0x02, ++ 0x20, 0x30, 0xc6, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc6, 0x18, 0x00, 0x02, ++ 0x20, 0x30, 0xc7, 0x18, 0x00, 0x02, 0x20, 0xf0, 0xc3, 0x18, 0x00, 0x02, ++ 0x20, 0xf0, 0xc1, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc0, 0x18, 0x00, 0x02, ++ 0x20, 0x30, 0xc0, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc0, 0x18, 0x03, 0x02, ++ 0x20, 0x30, 0xf0, 0xfb, 0x03, 0x02, 0x20, 0x30, 0xf0, 0xf3, 0x01, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03}; +diff -ruN xv-3.10a-bugfixes/bits/br_pic2 xv-3.10a-enhancements/bits/br_pic2 +--- xv-3.10a-bugfixes/bits/br_pic2 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_pic2 2005-04-17 14:04:22.000000000 -0700 +@@ -0,0 +1,27 @@ ++#define br_pic2_width 48 ++#define br_pic2_height 48 ++static unsigned char br_pic2_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x3f, 0x3f, 0x1f, 0x1f, 0x02, ++ 0x20, 0x7f, 0xbf, 0xbf, 0x3f, 0x02, 0x20, 0x63, 0x8c, 0xb1, 0x31, 0x02, ++ 0x20, 0x63, 0x8c, 0x01, 0x30, 0x02, 0x20, 0x63, 0x8c, 0x01, 0x30, 0x02, ++ 0x20, 0x73, 0x8c, 0x01, 0x30, 0x02, 0x20, 0x3f, 0x8c, 0x01, 0x18, 0x02, ++ 0x20, 0x1f, 0x8c, 0x01, 0x0c, 0x02, 0x20, 0x03, 0x8c, 0x01, 0x06, 0x02, ++ 0x20, 0x03, 0x8c, 0x01, 0x03, 0x02, 0x20, 0x03, 0x8c, 0xb1, 0x01, 0x02, ++ 0x20, 0x03, 0xbf, 0xbf, 0x3f, 0x02, 0x20, 0x03, 0x3f, 0x9f, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03}; +diff -ruN xv-3.10a-bugfixes/bits/br_png xv-3.10a-enhancements/bits/br_png +--- xv-3.10a-bugfixes/bits/br_png 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_png 1996-06-13 14:32:08.000000000 -0700 +@@ -0,0 +1,28 @@ ++#define br_png_width 48 ++#define br_png_height 48 ++static unsigned char br_png_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0xf8, 0x19, 0xc3, 0x07, 0x02, 0x20, 0x18, 0x3b, 0x63, 0x0c, 0x02, ++ 0x20, 0x18, 0x3b, 0x33, 0x00, 0x02, 0x20, 0x18, 0x5b, 0x33, 0x00, 0x02, ++ 0x20, 0xf8, 0x59, 0x33, 0x0f, 0x02, 0x20, 0x18, 0x98, 0x33, 0x0c, 0x02, ++ 0x20, 0x18, 0x98, 0x33, 0x0c, 0x02, 0x20, 0x18, 0x18, 0x63, 0x0c, 0x02, ++ 0x20, 0x18, 0x18, 0xc3, 0x0b, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03, ++ }; +diff -ruN xv-3.10a-bugfixes/bits/br_zx xv-3.10a-enhancements/bits/br_zx +--- xv-3.10a-bugfixes/bits/br_zx 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/bits/br_zx 1998-08-06 13:00:03.000000000 -0700 +@@ -0,0 +1,28 @@ ++#define br_zx_width 48 ++#define br_zx_height 48 ++static unsigned char br_zx_bits[] = { ++ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x7f, 0xce, 0x01, 0x0e, 0x02, 0x20, 0x61, 0x84, 0x00, 0x11, 0x02, ++ 0x20, 0x30, 0x48, 0x00, 0x10, 0x02, 0x20, 0x18, 0x38, 0x10, 0x08, 0x02, ++ 0x20, 0x0c, 0x30, 0x10, 0x0e, 0x02, 0x20, 0x06, 0x68, 0x7c, 0x10, 0x02, ++ 0x20, 0x03, 0x48, 0x10, 0x10, 0x02, 0x20, 0x41, 0x84, 0x10, 0x11, 0x02, ++ 0x20, 0x7f, 0xce, 0x01, 0x0e, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xff, 0xff, 0xff, 0xff, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x40, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02, ++ 0x20, 0x00, 0x00, 0x00, 0x10, 0x02, 0x20, 0x00, 0x00, 0x00, 0x08, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0x84, 0x03, 0x20, 0x00, 0x00, 0x00, 0xc2, 0x03, ++ 0x20, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x20, 0x00, 0x00, 0x80, 0xf0, 0x02, ++ 0x20, 0x00, 0x00, 0x40, 0x78, 0x02, 0x20, 0x00, 0x00, 0x20, 0x3c, 0x02, ++ 0x20, 0x00, 0x00, 0x10, 0x1e, 0x02, 0x20, 0x00, 0x00, 0x08, 0x0f, 0x03, ++ 0x20, 0x00, 0x00, 0x84, 0x87, 0x03, 0x20, 0x00, 0x00, 0xc2, 0xc3, 0x03, ++ 0x20, 0x00, 0x00, 0xe1, 0xe1, 0x03, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03, ++ }; +diff -ruN xv-3.10a-bugfixes/config.h xv-3.10a-enhancements/config.h +--- xv-3.10a-bugfixes/config.h 2005-03-21 23:21:31.000000000 -0800 ++++ xv-3.10a-enhancements/config.h 2005-04-30 23:52:42.000000000 -0700 +@@ -6,26 +6,46 @@ + /*************************************************************************** + * GZIP'd file support + * +- * if you have the gnu uncompression utility 'gunzip', XV can use it to +- * automatically 'unzip' any gzip'd files. To enable this feature, +- * change 'undef' to 'define' in the following line. Needless to say, if +- * your gunzip is installed elsewhere on your machine, change the 'GUNZIP' +- * definition appropriately. (use 'which gunzip' to find if you have gunzip, +- * and where it lives) ++ * if you have the GNU uncompression utility 'gunzip' (or 'gzip' itself, ++ * which is just a link to gunzip), XV can use it to automatically 'unzip' ++ * any gzip'd files. To enable this feature, change 'undef' to 'define' in ++ * the following line. Needless to say, if your gunzip is installed elsewhere ++ * on your machine, change the 'GUNZIP' definition appropriately. (use ++ * 'which gunzip' to find if you have gunzip, and where it lives; ditto for ++ * gzip) + */ +-#undef USE_GUNZIP ++#define USE_GUNZIP + + #ifdef USE_GUNZIP + # ifdef VMS + # define GUNZIP "UNCOMPRESS" + # else +-/* define GUNZIP "/usr/local/bin/gunzip -q" */ +-# define GUNZIP "/usr/bin/gzip -dq" /* more portable */ ++# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__) ++# define GUNZIP "/usr/bin/gzip -dq" ++# else ++# define GUNZIP "/usr/local/bin/gzip -dq" /* is full path truly needed? */ ++# endif + # endif + #endif + + + /*************************************************************************** ++ * BZIP2'd file support ++ * ++ * if you have the uncompression utility 'bunzip2' (or 'bzip2' itself, which ++ * is just a link to bunzip2), XV can use it to automatically 'unzip' any ++ * bzip2'd files. To enable this feature, change 'undef' to 'define' in the ++ * following line (if not already done). Use 'which bunzip2' or 'which bzip2' ++ * to find if you have bzip2/bunzip2, and where it lives. ++ */ ++#define USE_BUNZIP2 ++ ++#ifdef USE_BUNZIP2 ++# define BUNZIP2 "bzip2 -d" /* should this include the full path? */ ++#endif ++ ++ ++/*************************************************************************** + * compress'd file support + * + * if you have GUNZIP defined above, just ignore this, as 'gunzip' can +@@ -38,7 +58,14 @@ + */ + #define UNCOMPRESS "/usr/ucb/uncompress" + +-#if defined(hpux) || defined(SVR4) || defined(__386BSD__) ++#if defined(hpux) || defined(SVR4) || \ ++ defined(__386BSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ ++ defined(__linux__) ++ /* ++ I want to use BSD macro for checking if this OS is *BSD or not, ++ but the macro is defined in <sys/parm.h>, which I don't know all ++ machine has or not. ++ */ + # undef UNCOMPRESS + # define UNCOMPRESS "/usr/bin/uncompress" + #endif +@@ -90,6 +117,7 @@ + */ + + /* #define GS_PATH "/usr/local/bin/gs" */ ++#define GS_PATH "/usr/bin/gs" + /* #define GS_LIB "." */ + /* #define GS_DEV "ppmraw" */ + +@@ -120,3 +148,201 @@ + + #define BACKING_STORE + ++ ++/*************************************************************************** ++ * PhotoCD/MAG/PIC/MAKI/Pi/PIC2/HIPS format Support: ++ * ++ * if, for whatever reason--say, security concerns--you don't want to ++ * include support for one or more of the PhotoCD, MAG/MAKI/Pi/PIC/PIC2 ++ * (Japanese), or HIPS (astronomical) image formats, change the relevant ++ * 'define' to 'undef' in the following lines. Conversely, if you *do* ++ * want them, change 'undef' to 'define' as appropriate. ++ */ ++ ++#define HAVE_PCD /* believed to be reasonably safe */ ++ ++#undef HAVE_MAG /* probable security issues */ ++#undef HAVE_MAKI /* probable security issues */ ++#undef HAVE_PI /* probable security issues */ ++#undef HAVE_PIC /* probable security issues */ ++#undef HAVE_PIC2 /* probable security issues */ ++ ++#undef HAVE_HIPS /* probable security issues */ ++ ++ ++/*************************************************************************** ++ * MacBinary file support: ++ * ++ * if you want XV to be able to handle ``MacBinary'' files (which have ++ * 128 byte info file header at the head), change 'undef' to 'define' ++ * in the following line. ++ */ ++ ++#undef MACBINARY ++ ++ ++/*************************************************************************** ++ * Auto Expand support: ++ * ++ * if you want to extract archived file automatically and regard it as ++ * a directory, change 'undef' to 'define' in the AUTO_EXPAND line. ++ * ++ * Virtual Thumbdir support: ++ * ++ * if you want Virtual directory based Thumbdir(It means that XV ++ * doesn't forget builded Icons still be quited even if the directory ++ * is read-only), change 'undef' to 'define' the VIRTUAL_TD line. ++ */ ++ ++#undef AUTO_EXPAND ++#undef VIRTUAL_TD ++ ++#if defined(VIRTUAL_TD) && !defined(AUTO_EXPAND) ++# undef VIRTUAL_TD ++#endif ++ ++ ++/*************************************************************************** ++ * Adjust the aspect ratio of Icons: ++ * ++ * if you want to adjust the aspect ratio of the icons in Visual ++ * Schnauzer, change 'undef' to 'define' in the following line. ++ */ ++ ++#undef VS_ADJUST ++ ++ ++/*************************************************************************** ++ * Restore original colormap: ++ * ++ * if you want to restore original colormap when icons in Visual ++ * Shunauzer is double-clicked, change 'undef' to 'define' in the ++ * following line. ++ */ ++ ++#undef VS_RESCMAP ++ ++ ++/*************************************************************************** ++ * TextViewer l10n support: ++ * ++ * if you want XV to show the text in Japanese on TextViewer, change ++ * 'undef' to 'define' in the following line. ++ */ ++ ++#undef TV_L10N ++ ++#ifdef TV_L10N ++/* ++ * if you want to change the default code-set used in case that XV ++ * fails to select correct code-set, uncomment the '#define ++ * LOCALE_DEFAULT' line and change the 'LOCALE_DEFAULT' definition ++ * appropriately. ++ * (0:ASCII, 1:EUC-j, 2:JIS, 3:MS Kanji) */ ++ ++/* # define LOCALE_DEFAULT 0 */ ++ ++/* ++ * Uncomment and edit the following lines, if your X Window System was ++ * not compiled with -DX_LOCALE and you failed to display the Japanese ++ * text in TextViewer. You don't have to write locale name of JIS code-set ++ * and Microsoft code-set, if your system doesn't support those code-sets. ++ */ ++ ++/* ++# define LOCALE_NAME_EUC "ja_JP.EUC" ++# define LOCALE_NAME_JIS "ja_JP.JIS" ++# define LOCALE_NAME_MSCODE "ja_JP.SJIS" ++*/ ++ ++/* ++ * if your system doesn't have the Japanese fonts in the sizes, ++ * Uncomment and edit the following font size entries. ++ */ ++ ++/* # define TV_FONTSIZE 14,16,24 */ ++ ++/* ++ * If you need, uncomment and modify the following font name. ++ */ ++ ++/* # define TV_FONTSET "-*-fixed-medium-r-normal--%d-*" */ ++#endif /* TV_L10N */ ++ ++ ++/*************************************************************************** ++ * User definable filter support: ++ * ++ * Use the filters as input and output method for load and save unsupported ++ * image format file. The filter command is recognized by definition of ++ * magic number or suffix in "~/.xv_mgcsfx" . ++ * To enable this feature, change 'undef' to 'define' in the following line. ++ */ ++#undef HAVE_MGCSFX ++ ++#ifdef HAVE_MGCSFX ++/* ++ * Support symbol 'auto' as <input image type> in startup file. This type ++ * cannot use pipe as input; it writes to a temporary file and recognizes ++ * the actual filetype by XV processing. ++ */ ++# define HAVE_MGCSFX_AUTO ++ ++/* ++ * The startup file of definition for MgcSfx. 'MGCSFX_SITE_RC' is read ++ * first and '~/MGCSFX_RC' is second. So same definitions in both files ++ * are overridden by '~/MGCSFX_RC' ++ * To define startup file, see the sample of startup file 'xv_mgcsfx.sample'. ++ */ ++# define MGCSFX_SITE_RC "xv_mgcsfx" ++# define MGCSFX_RC ".xv_mgcsfx" ++ ++/* ++ * If you want startup file to pass preprocessor in reading time, then ++ * change 'undef' to 'define' in the following line. ++ * ++ * WARNING : If you decide to use preprocessor, you must not write ++ * '# <comment>' style comment in startup file. Because, ++ * preprocessor can't recognize. */ ++# undef USE_MGCSFX_PREPROCESSOR ++ ++# ifdef USE_MGCSFX_PREPROCESSOR ++/* ++ * This is used like "system("MGCSFX_PREPROCESSOR MGCSFX_RC > tmp_name");", ++ * and read tmp_name instead of MGCSFX_RC. ++ */ ++# define MGCSFX_PREPROCESSOR "/usr/lib/cpp" ++/* # define MGCSFX_PREPROCESSOR "cc -E" */ ++ ++# endif /* USE_MGCSFX_PREPROCESSOR */ ++ ++/* ++ * Default string of command. If input command is required for undefined file, ++ * dialog is popuped with 'MGCSFX_DEFAULT_INPUT_COMMAND'. And, if output ++ * command is required in save dialog of MgcSfx, dialog is popuped with ++ * 'MGCSFX_DEFAULT_OUTPUT_COMMAND'. ++ * ++ * WARNING : Now, supported only 'PNM' image format, when command input is ++ * required. You should define filter which use 'PNM' image format ++ * as input or output. ++ */ ++# define MGCSFX_DEFAULT_INPUT_COMMAND "tifftopnm" ++# define MGCSFX_DEFAULT_OUTPUT_COMMAND "pnmtotiff" ++ ++#endif /* HAVE_MGCSFX */ ++ ++ ++/*************************************************************************** ++ * Multi-Lingual TextViewer ++ * ++ * if you want XV to show the text in multi-lingual on TextViewer, change ++ * 'undef' to 'define' in the following line. ++ */ ++ ++#undef TV_MULTILINGUAL ++ ++#define TV_DEFAULT_CODESET TV_EUC_JAPAN ++ ++#ifdef TV_MULTILINGUAL ++# undef TV_L10N ++#endif +diff -ruN xv-3.10a-bugfixes/tiff/Makefile xv-3.10a-enhancements/tiff/Makefile +--- xv-3.10a-bugfixes/tiff/Makefile 2004-05-16 18:49:11.000000000 -0700 ++++ xv-3.10a-enhancements/tiff/Makefile 2005-04-17 14:45:28.000000000 -0700 +@@ -38,7 +38,7 @@ + IPATH= -I. + + COPTS= -O +-CFLAGS= ${COPTS} ${IPATH} ++CFLAGS= ${COPTS} ${IPATH} -D_BSD_SOURCE + + INCS= tiff.h tiffio.h + +diff -ruN xv-3.10a-bugfixes/vdcomp.c xv-3.10a-enhancements/vdcomp.c +--- xv-3.10a-bugfixes/vdcomp.c 2005-03-20 17:48:59.000000000 -0800 ++++ xv-3.10a-enhancements/vdcomp.c 2005-04-17 22:59:39.000000000 -0700 +@@ -106,6 +106,7 @@ + !defined(pyr) && \ + !defined(__UMAXV__) && \ + !defined(bsd43) && \ ++ !defined(__bsd43) && \ + !defined(aux) && \ + !defined(__bsdi__) && \ + !defined(sequent) && \ +@@ -115,7 +116,14 @@ + # if defined(hp300) || defined(hp800) || defined(NeXT) + # include <sys/malloc.h> /* it's in 'sys' on HPs and NeXT */ + # else +-# include <malloc.h> ++# if !defined(__386BSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) ++ /* ++ I want to use BSD macro for checking if this OS is *BSD or not, ++ but the macro is defined in <sys/parm.h>, which I don't know all ++ machine has or not. ++ */ ++# include <malloc.h> ++# endif + # endif + # endif + #endif /* !VMS */ +diff -ruN xv-3.10a-bugfixes/xcmap.c xv-3.10a-enhancements/xcmap.c +--- xv-3.10a-bugfixes/xcmap.c 2005-03-20 15:51:59.000000000 -0800 ++++ xv-3.10a-enhancements/xcmap.c 2005-04-17 14:45:28.000000000 -0700 +@@ -163,7 +163,7 @@ + XSetBackground(theDisp,theGC,bcol); + + CreateMainWindow(cmd,geom,argc,argv); +- Resize(WIDE,HIGH); ++ Resize((int)WIDE,(int)HIGH); + + XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask + | StructureNotifyMask | ButtonPressMask); +@@ -212,10 +212,10 @@ + + case ConfigureNotify: { + XConfigureEvent *conf_event = (XConfigureEvent *) event; ++ int w = conf_event->width, h = conf_event->height; + +- if (conf_event->window == mainW && +- (conf_event->width != WIDE || conf_event->height != HIGH)) +- Resize(conf_event->width, conf_event->height); ++ if (conf_event->window == mainW && (w != WIDE || h != HIGH)) ++ Resize((int)(w ? w : WIDE), (int)(h ? h : HIGH)); + } + break; + +@@ -274,6 +274,8 @@ + WIDE = HIGH = 256; /* default window size */ + + x=y=w=h=1; ++ hints.flags = 0; ++ + i=XParseGeometry(geom,&x,&y,&w,&h); + if (i&WidthValue) + { +diff -ruN xv-3.10a-bugfixes/xv.c xv-3.10a-enhancements/xv.c +--- xv-3.10a-bugfixes/xv.c 2005-03-20 22:25:22.000000000 -0800 ++++ xv-3.10a-enhancements/xv.c 2005-05-01 13:33:25.000000000 -0700 +@@ -62,6 +62,19 @@ + + static char basefname[128]; /* just the current fname, no path */ + ++#ifdef TV_L10N ++# ifndef TV_FONTSET ++# define TV_FONTSET "-*-fixed-medium-r-normal--%d-*" ++# endif ++# ifndef TV_FONTSIZE ++# define TV_FONTSIZE 14,16 ++# endif ++ ++static int mfontsize[] = { TV_FONTSIZE, 0 }; ++static char mfontset[256]; ++#endif ++ ++ + /* things to do upon successfully loading an image */ + static int autoraw = 0; /* force raw if using stdcmap */ + static int autodither = 0; /* dither */ +@@ -78,6 +91,12 @@ + + static int force8 = 0; /* force 8-bit mode */ + static int force24 = 0; /* force 24-bit mode */ ++#ifdef HAVE_PCD ++static int PcdSize = -1; /* force dialog to ask */ ++#endif ++ ++static float waitsec_nonfinal = -1; /* "normal" waitsec value */ ++static float waitsec_final = -1; /* final-image waitsec value */ + + /* used in DeleteCmd() and Quit() */ + static char **mainargv; +@@ -103,7 +122,6 @@ + static void openNextLoop PARM((void)); + static void openPrevPic PARM((void)); + static void openNamedPic PARM((void)); +-static int findRandomPic PARM((void)); + static void mainLoop PARM((void)); + static void createMainWindow PARM((char *, char *)); + static void setWinIconNames PARM((char *)); +@@ -120,16 +138,17 @@ + int imap, ctrlmap, gmap, browmap, cmtmap, clrroot, nopos, limit2x; + char *display, *whitestr, *blackstr, *histr, *lostr, + *infogeom, *fgstr, *bgstr, *ctrlgeom, *gamgeom, *browgeom, *tmpstr; +-char *rootfgstr, *rootbgstr, *visualstr, *textgeom, *cmtgeom; ++char *rootfgstr, *rootbgstr, *imagebgstr, *visualstr, *textgeom, *cmtgeom; + char *monofontname, *flistName; ++#ifdef TV_L10N ++char **misscharset, *defstr; ++int nmisscharset; ++#endif + int curstype, stdinflag, browseMode, savenorm, preview, pscomp, preset, + rmodeset, gamset, cgamset, perfect, owncmap, rwcolor, stdcmap; + int nodecor; + double gamval, rgamval, ggamval, bgamval; + +- +- +- + /*******************************************/ + int main(argc, argv) + int argc; +@@ -137,6 +156,9 @@ + /*******************************************/ + { + int i; ++#ifdef TV_L10N ++ int j; ++#endif + XColor ecdef; + Window rootReturn, parentReturn, *children; + unsigned int numChildren, rootDEEP; +@@ -153,6 +175,13 @@ + /*** variable Initialization ***/ + /*****************************************************/ + ++#ifdef TV_L10N ++ /* setlocale(LC_ALL, localeList[LOCALE_EUCJ]); */ ++ setlocale(LC_ALL, ""); ++ xlocale = (int)XSupportsLocale(); /* assume that (Bool) is (int) */ ++ /* if X doesn't support ja_JP.ujis text viewer l10n doesn't work. */ ++#endif ++ + xv_getwd(initdir, sizeof(initdir)); + searchdir[0] = '\0'; + fullfname[0] = '\0'; +@@ -162,7 +191,7 @@ + + /* init internal variables */ + display = NULL; +- fgstr = bgstr = rootfgstr = rootbgstr = NULL; ++ fgstr = bgstr = rootfgstr = rootbgstr = imagebgstr = NULL; + histr = lostr = whitestr = blackstr = NULL; + visualstr = monofontname = flistName = NULL; + winTitle = NULL; +@@ -180,6 +209,7 @@ + autoclose = autoDelete = 0; + cmapInGam = 0; + grabDelay = 0; ++ startGrab = 0; + showzoomcursor = 0; + perfect = owncmap = stdcmap = rwcolor = 0; + +@@ -228,6 +258,10 @@ + if (!tmpdir) FatalError("can't malloc 'tmpdir'\n"); + strcpy(tmpdir, tmpstr); + } ++#ifdef AUTO_EXPAND ++ Vdinit(); ++ vd_handler_setup(); ++#endif + + /* init command-line options flags */ + infogeom = DEFINFOGEOM; ctrlgeom = DEFCTRLGEOM; +@@ -238,7 +272,7 @@ + ninstall = 0; fixedaspect = 0; noFreeCols = nodecor = 0; + DEBUG = 0; bwidth = 2; + nolimits = useroot = clrroot = noqcheck = 0; +- waitsec = -1; waitloop = 0; automax = 0; ++ waitsec = waitsec_final = -1.0; waitloop = 0; automax = 0; + rootMode = 0; hsvmode = 0; + rmodeset = gamset = cgamset = 0; + nopos = limit2x = 0; +@@ -251,6 +285,10 @@ + preset = 0; + viewonly = 0; + ++#ifdef ENABLE_FIXPIX_SMOOTH ++ do_fixpix_smooth = 0; ++#endif ++ + /* init 'xormasks' array */ + xorMasks[0] = 0x01010101; + xorMasks[1] = 0x02020203; +@@ -277,6 +315,24 @@ + tiffW = (Window) NULL; tiffUp = 0; + #endif + ++#ifdef HAVE_PNG ++ pngW = (Window) NULL; pngUp = 0; ++#endif ++ ++ pcdW = (Window) NULL; pcdUp = 0; ++ ++#ifdef HAVE_PIC2 ++ pic2W = (Window) NULL; pic2Up = 0; ++#endif ++ ++#ifdef HAVE_PCD ++ pcdW = (Window) NULL; pcdUp = 0; ++#endif ++ ++#ifdef HAVE_MGCSFX ++ mgcsfxW = (Window) NULL; mgcsfxUp = 0; ++#endif ++ + imap = ctrlmap = gmap = browmap = cmtmap = 0; + + ch_offx = ch_offy = p_offx = p_offy = 0; +@@ -303,13 +359,35 @@ + verifyArgs(); + + ++#if 0 ++#ifdef XVEXECPATH ++ /* set up path to search for external executables */ ++ { ++ char *systempath = getenv("PATH"); ++ char *xvexecpath = getenv("XVPATH"); ++ if (xvexecpath == NULL) xvexecpath = XVEXECPATH; ++ /* FIXME: can systempath == NULL? */ ++ strcat(systempath, ":"); /* FIXME: writing to mem we don't own */ ++ strcat(systempath, xvexecpath); /* FIXME: writing to mem we don't own */ ++ /* FIXME: was there supposed to be a setenv() call in here? */ ++ if (DEBUG) ++ fprintf(stderr, "DEBUG: executable search path: %s\n", systempath); ++ } ++#endif ++#endif ++ ++ + /*****************************************************/ + /*** X Setup ***/ + /*****************************************************/ + + theScreen = DefaultScreen(theDisp); + theCmap = DefaultColormap(theDisp, theScreen); +- rootW = RootWindow(theDisp,theScreen); ++ if (spec_window) { ++ rootW = spec_window; ++ } else { ++ rootW = RootWindow(theDisp,theScreen); ++ } + theGC = DefaultGC(theDisp,theScreen); + theVisual = DefaultVisual(theDisp,theScreen); + ncells = DisplayCells(theDisp, theScreen); +@@ -320,7 +398,7 @@ + + rootDEEP = dispDEEP; + +- /* things dependant on theVisual: ++ /* things dependent on theVisual: + * dispDEEP, theScreen, rootW, ncells, theCmap, theGC, + * vrWIDE, dispWIDE, vrHIGH, dispHIGH, maxWIDE, maxHIGH + */ +@@ -500,6 +578,7 @@ + arrow = XCreateFontCursor(theDisp,(u_int) curstype); + cross = XCreateFontCursor(theDisp,XC_crosshair); + tcross = XCreateFontCursor(theDisp,XC_tcross); ++ tlcorner = XCreateFontCursor(theDisp,XC_top_left_corner); + zoom = XCreateFontCursor(theDisp,XC_sizing); + + { +@@ -575,6 +654,18 @@ + xvAllocColor(theDisp, theCmap, &ecdef)) rootbg = ecdef.pixel; + + ++ /* GRR 19980308: set up image bg color (for transparent images) */ ++ have_imagebg = 0; ++ if (imagebgstr && XParseColor(theDisp, theCmap, imagebgstr, &ecdef) && ++ xvAllocColor(theDisp, theCmap, &ecdef)) { ++ /* imagebg = ecdef.pixel; */ ++ have_imagebg = 1; ++ imagebgR = ecdef.red; ++ imagebgG = ecdef.green; ++ imagebgB = ecdef.blue; ++ } ++ ++ + /* set up hi/lo colors */ + i=0; + if (dispDEEP > 1) { /* only if we're on a reasonable display */ +@@ -664,6 +755,61 @@ + + monofont=monofinfo->fid; + ++#ifdef TV_L10N ++ if (xlocale) { ++ i = 0; ++ while (mfontsize[i]) { ++ xlocale = 1; /* True */ ++ ++ sprintf(mfontset, TV_FONTSET, mfontsize[i]); ++/*fprintf(stderr, "FontSet: %s\n", mfontset);*/ ++ ++ monofset = XCreateFontSet(theDisp, mfontset, ++ &misscharset, &nmisscharset, &defstr); ++# if 0 /* not useful */ ++ if (!monofset) { ++ /* the current locale is not supported */ ++/*fprintf(stderr, "Current locale `%s' is not supported.\n", localeList[i]);*/ ++ xlocale = 0; ++ break; ++ } ++# endif ++/*fprintf(stderr, "# of misscharset in mfontsize[%d]: %d\n", i,nmisscharset);*/ ++ ++ for (j = 0; j < nmisscharset; j++) { ++ if (!strncmp(misscharset[j], "jisx0208", 8)) { ++ /* font for JIS X 0208 is not found */ ++ xlocale = 0; ++ break; ++ } ++ } ++ ++ if (xlocale) { ++ monofsetinfo = XExtentsOfFontSet(monofset); ++ monofsetinfo->max_logical_extent.width = mfontsize[i]; ++ /* correct size of TextViewer ++ in case that JIS X 0208 is not found */ ++ break; ++ } ++ ++ i++; ++ } /* while (mfontsize[i]) */ ++ ++# if 0 ++ if (nmisscharset > 0) { ++ sprintf(str,"missing %d charset:\n", nmisscharset); ++ for (i = 0; i < nmisscharset; i++) { ++ sprintf(str, "%s\t%s\n", str, misscharset[i]); ++ } ++# if 0 ++ FatalError(str); ++# else ++ fprintf(stderr, "%s", str); ++# endif ++ } ++# endif ++ } ++#endif /* TV_L10N */ + + + +@@ -693,6 +839,18 @@ + } + else namelist[0] = NULL; + } ++ else if (randomShow) { ++ int i, j; ++ char *tmp; ++ ++ srandom((int)time((time_t *)0)); ++ for (i = numnames; i > 1; i--) { ++ j = random() % i; ++ tmp = namelist[i-1]; ++ namelist[i-1] = namelist[j]; ++ namelist[j] = tmp; ++ } ++ } + + if (numnames) makeDispNames(); + +@@ -796,6 +954,25 @@ + XSetTransientForHint(theDisp, tiffW, dirW); + #endif + ++#ifdef HAVE_PNG ++ CreatePNGW(); ++ XSetTransientForHint(theDisp, pngW, dirW); ++#endif ++ ++#ifdef HAVE_PCD ++ CreatePCDW(); ++ XSetTransientForHint(theDisp, pcdW, dirW); ++#endif ++ ++#ifdef HAVE_PIC2 ++ CreatePIC2W(); ++ XSetTransientForHint(theDisp, pic2W, dirW); ++#endif ++ ++#ifdef HAVE_MGCSFX ++ CreateMGCSFXW(); ++ XSetTransientForHint(theDisp, mgcsfxW, dirW); ++#endif + + LoadFishCursors(); + SetCursors(-1); +@@ -964,7 +1141,11 @@ + + dispDEEP = vinfo[best].depth; + theScreen = vinfo[best].screen; +- rootW = RootWindow(theDisp, theScreen); ++ if (spec_window) { ++ rootW = spec_window; ++ } else { ++ rootW = RootWindow(theDisp,theScreen); ++ } + ncells = vinfo[best].colormap_size; + theCmap = XCreateColormap(theDisp, rootW, theVisual, AllocNone); + +@@ -1095,6 +1276,9 @@ + + if (rd_str ("fileList")) flistName = def_str; + if (rd_flag("fixed")) fixedaspect = def_int; ++#ifdef ENABLE_FIXPIX_SMOOTH ++ if (rd_flag("fixpix")) do_fixpix_smooth = def_int; ++#endif + if (rd_flag("force8")) force8 = def_int; + if (rd_flag("force24")) force24 = def_int; + if (rd_str ("foreground")) fgstr = def_str; +@@ -1106,21 +1290,37 @@ + if (rd_str ("highlight")) histr = def_str; + if (rd_str ("iconGeometry")) icongeom = def_str; + if (rd_flag("iconic")) startIconic = def_int; ++ if (rd_str ("imageBackground")) imagebgstr = def_str; + if (rd_str ("infoGeometry")) infogeom = def_str; + if (rd_flag("infoMap")) imap = def_int; + if (rd_flag("loadBrowse")) browseMode = def_int; + if (rd_str ("lowlight")) lostr = def_str; ++#ifdef MACBINARY ++ if (rd_flag("macbinary")) handlemacb = def_int; ++#endif ++#ifdef HAVE_MGCSFX ++ if (rd_flag("mgcsfx")) mgcsfx = def_int; ++#endif + if (rd_flag("mono")) mono = def_int; + if (rd_str ("monofont")) monofontname = def_str; + if (rd_int ("ncols")) ncols = def_int; + if (rd_flag("ninstall")) ninstall = def_int; + if (rd_flag("nodecor")) nodecor = def_int; + if (rd_flag("nolimits")) nolimits = def_int; ++#ifdef HAVE_MGCSFX ++ if (rd_flag("nomgcsfx")) nomgcsfx = def_int; ++#endif ++#if defined(HAVE_PIC) || defined(HAVE_PIC2) ++ if (rd_flag("nopicadjust")) nopicadjust = def_int; ++#endif + if (rd_flag("nopos")) nopos = def_int; + if (rd_flag("noqcheck")) noqcheck = def_int; + if (rd_flag("nostat")) nostat = def_int; + if (rd_flag("ownCmap")) owncmap = def_int; + if (rd_flag("perfect")) perfect = def_int; ++#ifdef HAVE_PIC2 ++ if (rd_flag("pic2split")) pic2split = def_int; ++#endif + if (rd_flag("popupKludge")) winCtrPosKludge = def_int; + if (rd_str ("print")) strncpy(printCmd, def_str, + (size_t) PRINTCMDLEN); +@@ -1138,6 +1338,9 @@ + if (rd_str ("textviewGeometry")) textgeom = def_str; + if (rd_flag("useStdCmap")) stdcmap = def_int; + if (rd_str ("visual")) visualstr = def_str; ++#ifdef VS_ADJUST ++ if (rd_flag("vsadjust")) vsadjust = def_int; ++#endif + if (rd_flag("vsDisable")) novbrowse = def_int; + if (rd_str ("vsGeometry")) browgeom = def_str; + if (rd_flag("vsMap")) browmap = def_int; +@@ -1172,7 +1375,13 @@ + } + + if (numnames<MAXNAMES) { ++#ifdef AUTO_EXPAND ++ if(Isarchive(argv[i]) == 0){ /* Not archive file */ ++ namelist[numnames++] = argv[i]; ++ } ++#else + namelist[numnames++] = argv[i]; ++#endif + if (numnames==MAXNAMES) { + fprintf(stderr,"%s: too many filenames. Only using first %d.\n", + cmd, MAXNAMES); +@@ -1198,6 +1407,14 @@ + } + } + ++ else if (!argcmp(argv[i],"-windowid",3,0,&pm)) { ++ if (++i<argc) { ++ if (sscanf(argv[i], "%ld", &spec_window) != 1) { ++ fprintf(stderr,"%s: bad argument to -windowid '%s'\n",cmd,argv[i]); ++ } ++ } ++ } ++ + else if (!argcmp(argv[i],"-best24",3,0,&pm)) /* -best */ + conv24 = CONV24_BEST; + +@@ -1289,7 +1506,11 @@ + else if (!argcmp(argv[i],"-fg",3,0,&pm)) /* fg color */ + { if (++i<argc) fgstr = argv[i]; } + +- else if (!argcmp(argv[i],"-fixed",3,1,&fixedaspect)); /* fix asp. ratio */ ++ else if (!argcmp(argv[i],"-fixed",5,1,&fixedaspect)); /* fix asp. ratio */ ++ ++#ifdef ENABLE_FIXPIX_SMOOTH ++ else if (!argcmp(argv[i],"-fixpix",5,1,&do_fixpix_smooth)); /* dithering */ ++#endif + + else if (!argcmp(argv[i],"-flist",3,0,&pm)) /* file list */ + { if (++i<argc) flistName = argv[i]; } +@@ -1330,6 +1551,10 @@ + { if (++i<argc) infogeom = argv[i]; } + + else if (!argcmp(argv[i],"-imap", 3,1,&imap)); /* imap */ ++ ++ else if (!argcmp(argv[i],"-ibg",3,0,&pm)) /* GRR: image background color */ ++ { if (++i<argc) imagebgstr = argv[i]; } ++ + else if (!argcmp(argv[i],"-lbrowse", 3,1,&browseMode)); /* browse mode */ + + else if (!argcmp(argv[i],"-lo",3,0,&pm)) /* lowlight */ +@@ -1354,9 +1579,17 @@ + else if (!argcmp(argv[i],"-maxpect",5,1,&pm)) /* auto maximize */ + { automax=pm; fixedaspect=pm; } + ++#ifdef MACBINARY ++ else if (!argcmp(argv[i],"-macbinary",3,1,&handlemacb)); /* macbinary */ ++#endif ++ + else if (!argcmp(argv[i],"-mfn",3,0,&pm)) /* mono font name */ + { if (++i<argc) monofontname = argv[i]; } + ++#ifdef HAVE_MGCSFX ++ else if (!argcmp(argv[i],"-mgcsfx", 4,1,&mgcsfx)); /* mgcsfx */ ++#endif ++ + else if (!argcmp(argv[i],"-mono",3,1,&mono)); /* mono */ + + else if (!argcmp(argv[i],"-name",3,0,&pm)) /* name */ +@@ -1365,17 +1598,30 @@ + else if (!argcmp(argv[i],"-ncols",3,0,&pm)) /* ncols */ + { if (++i<argc) ncols=abs(atoi(argv[i])); } + +- else if (!argcmp(argv[i],"-ninstall", 3,1,&ninstall)); /* inst cmaps?*/ ++ else if (!argcmp(argv[i],"-ninstall", 3,1,&ninstall)); /* inst cmaps? */ + else if (!argcmp(argv[i],"-nodecor", 4,1,&nodecor)); + else if (!argcmp(argv[i],"-nofreecols",4,1,&noFreeCols)); + else if (!argcmp(argv[i],"-nolimits", 4,1,&nolimits)); /* nolimits */ ++#ifdef HAVE_MGCSFX ++ else if (!argcmp(argv[i],"-nomgcsfx", 4,1,&nomgcsfx)); /* nomgcsfx */ ++#endif ++#if defined(HAVE_PIC) || defined(HAVE_PIC2) ++ else if (!argcmp(argv[i],"-nopicadjust", 4,1,&nopicadjust));/*nopicadjust*/ ++#endif + else if (!argcmp(argv[i],"-nopos", 4,1,&nopos)); /* nopos */ + else if (!argcmp(argv[i],"-noqcheck", 4,1,&noqcheck)); /* noqcheck */ +- else if (!argcmp(argv[i],"-noresetroot",5,1,&resetroot)); /* reset root*/ ++ else if (!argcmp(argv[i],"-noresetroot",5,1,&resetroot)); /* reset root */ + else if (!argcmp(argv[i],"-norm", 5,1,&autonorm)); /* norm */ + else if (!argcmp(argv[i],"-nostat", 4,1,&nostat)); /* nostat */ + else if (!argcmp(argv[i],"-owncmap", 2,1,&owncmap)); /* own cmap */ ++#ifdef HAVE_PCD ++ else if (!argcmp(argv[i],"-pcd", 4,0,&pm)) /* pcd with size */ ++ { if (i+1<argc) PcdSize = atoi(argv[++i]); } ++#endif + else if (!argcmp(argv[i],"-perfect", 3,1,&perfect)); /* -perfect */ ++#ifdef HAVE_PIC2 ++ else if (!argcmp(argv[i],"-pic2split", 3,1,&pic2split)); /* pic2split */ ++#endif + else if (!argcmp(argv[i],"-pkludge", 3,1,&winCtrPosKludge)); + else if (!argcmp(argv[i],"-poll", 3,1,&polling)); /* chk mod? */ + +@@ -1418,6 +1664,7 @@ + conv24 = CONV24_SLOW; + + else if (!argcmp(argv[i],"-smooth",3,1,&autosmooth)); /* autosmooth */ ++ else if (!argcmp(argv[i],"-startgrab",3,1,&startGrab)); /* startGrab */ + else if (!argcmp(argv[i],"-stdcmap",3,1,&stdcmap)); /* use stdcmap */ + + else if (!argcmp(argv[i],"-tgeometry",2,0,&pm)) /* textview geom */ +@@ -1429,6 +1676,10 @@ + else if (!argcmp(argv[i],"-visual",4,0,&pm)) /* visual */ + { if (++i<argc) visualstr = argv[i]; } + ++#ifdef VS_ADJUST ++ else if (!argcmp(argv[i],"-vsadjust", 3,1,&vsadjust)); /* vsadjust */ ++#endif ++ + else if (!argcmp(argv[i],"-vsdisable",4,1,&novbrowse)); /* disable sch? */ + + else if (!argcmp(argv[i],"-vsgeometry",4,0,&pm)) /* visSchnauzer geom */ +@@ -1440,8 +1691,9 @@ + + else if (!argcmp(argv[i],"-wait",3,0,&pm)) { /* secs betwn pics */ + if (++i<argc) { +- waitsec = abs(atoi(argv[i])); +- if (waitsec<0) waitsec = 0; ++ char *comma = strchr(argv[i], ','); ++ waitsec_nonfinal = fabs(atof(argv[i])); ++ waitsec_final = comma? fabs(atof(comma+1)) : waitsec_nonfinal; + } + } + +@@ -1467,7 +1719,11 @@ + /* check options for validity */ + + if (strlen(searchdir)) { /* got a search directory */ ++#ifdef AUTO_EXPAND ++ if (Chvdir(searchdir)) { ++#else + if (chdir(searchdir)) { ++#endif + fprintf(stderr,"xv: unable to cd to directory '%s'.\n",searchdir); + fprintf(stderr, + " Ignoring '-dir' option and/or 'xv.searchDirectory' resource\n"); +@@ -1514,7 +1770,7 @@ + preset = 0; + } + +- if (waitsec < 0) noFreeCols = 0; /* disallow nfc if not doing slideshow */ ++ if (waitsec < 0.0) noFreeCols = 0; /* disallow nfc if not doing slideshow */ + if (noFreeCols && perfect) { perfect = 0; owncmap = 1; } + + /* decide what default color allocation stuff we've settled on */ +@@ -1556,6 +1812,20 @@ + + static void cmdSyntax() + { ++ /* GRR 19980605: added version info for most common libraries */ ++ fprintf(stderr, "XV - %s.\n", REVDATE); ++#ifdef HAVE_JPEG ++ VersionInfoJPEG(); ++#endif ++#ifdef HAVE_TIFF ++ VersionInfoTIFF(); ++#endif ++#ifdef HAVE_PNG ++ VersionInfoPNG(); ++#endif ++ /* pbm/pgm/ppm support is native, not via pbmplus/netpbm libraries */ ++ fprintf(stderr, "\n"); ++ + fprintf(stderr, "Usage:\n"); + printoption(cmd); + printoption("[-]"); +@@ -1595,6 +1865,9 @@ + printoption("[-expand exp | hexp:vexp]"); + printoption("[-fg color]"); + printoption("[-/+fixed]"); ++#ifdef ENABLE_FIXPIX_SMOOTH ++ printoption("[-/+fixpix]"); ++#endif + printoption("[-flist fname]"); + printoption("[-gamma val]"); + printoption("[-geometry geom]"); +@@ -1607,6 +1880,7 @@ + printoption("[-hi color]"); + printoption("[-/+hist]"); + printoption("[-/+hsv]"); ++ printoption("[-ibg color]"); /* GRR 19980314 */ + printoption("[-icgeometry geom]"); + printoption("[-/+iconic]"); + printoption("[-igeometry geom]"); +@@ -1614,9 +1888,15 @@ + printoption("[-/+lbrowse]"); + printoption("[-lo color]"); + printoption("[-/+loadclear]"); ++#ifdef MACBINARY ++ printoption("[-/+macbinary]"); ++#endif + printoption("[-/+max]"); + printoption("[-/+maxpect]"); + printoption("[-mfn font]"); ++#ifdef HAVE_MGCSFX ++ printoption("[-/+mgcsfx]"); ++#endif + printoption("[-/+mono]"); + printoption("[-name str]"); + printoption("[-ncols #]"); +@@ -1624,13 +1904,25 @@ + printoption("[-/+nodecor]"); + printoption("[-/+nofreecols]"); + printoption("[-/+nolimits]"); ++#ifdef HAVE_MGCSFX ++ printoption("[-/+nomgcsfx]"); ++#endif ++#if defined(HAVE_PIC) || defined(HAVE_PIC2) ++ printoption("[-/+nopicadjust]"); ++#endif + printoption("[-/+nopos]"); + printoption("[-/+noqcheck]"); + printoption("[-/+noresetroot]"); + printoption("[-/+norm]"); + printoption("[-/+nostat]"); + printoption("[-/+owncmap]"); ++#ifdef HAVE_PCD ++ printoption("[-pcd size(0=192*128,1,2,3,4=3072*2048)]"); ++#endif + printoption("[-/+perfect]"); ++#ifdef HAVE_PIC2 ++ printoption("[-/+pic2split]"); ++#endif + printoption("[-/+pkludge]"); + printoption("[-/+poll]"); + printoption("[-preset #]"); +@@ -1649,17 +1941,22 @@ + printoption("[-/+rw]"); + printoption("[-slow24]"); + printoption("[-/+smooth]"); ++ printoption("[-/+startgrab]"); + printoption("[-/+stdcmap]"); + printoption("[-tgeometry geom]"); + printoption("[-/+vflip]"); + printoption("[-/+viewonly]"); + printoption("[-visual type]"); ++#ifdef VS_ADJUST ++ printoption("[-/+vsadjust]"); ++#endif + printoption("[-/+vsdisable]"); + printoption("[-vsgeometry geom]"); + printoption("[-/+vsmap]"); + printoption("[-/+vsperfect]"); +- printoption("[-wait seconds]"); ++ printoption("[-wait secs[,final_secs]]"); + printoption("[-white color]"); ++ printoption("[-windowid windowid]"); + printoption("[-/+wloop]"); + printoption("[filename ...]"); + fprintf(stderr,"\n\n"); +@@ -1682,6 +1979,7 @@ + fprintf(stderr,"\t7: centered on a 'brick' background\n"); + fprintf(stderr,"\t8: symmetrical tiling\n"); + fprintf(stderr,"\t9: symmetrical mirrored tiling\n"); ++ fprintf(stderr,"\t10: upper left corner\n"); + fprintf(stderr,"\n"); + Quit(1); + } +@@ -1694,7 +1992,7 @@ + int *plusminus; + { + /* does a string compare between a1 and a2. To return '0', a1 and a2 +- must match to the length of a2, and that length has to ++ must match to the length of a1, and that length has to + be at least 'minlen'. Otherwise, return non-zero. plusminus set to '1' + if '-option', '0' if '+option' */ + +@@ -1734,6 +2032,10 @@ + char *tmp; + char *fullname, /* full name of the original file */ + filename[512]; /* full name of file to load (could be /tmp/xxx)*/ ++#ifdef MACBINARY ++ char origname[512]; /* file name of original file (NO processing) */ ++ origname[0] = '\0'; ++#endif + + xvbzero((char *) &pinfo, sizeof(PICINFO)); + +@@ -1866,8 +2168,22 @@ + frompipe = 1; + } + } ++#ifdef AUTO_EXPAND ++ else { ++ fullname = (char *) malloc(MAXPATHLEN+2); ++ strcpy(fullname, namelist[filenum]); ++ freename = 1; ++ } ++ tmp = (char *) rindex(fullname, '/'); ++ if (tmp) { ++ *tmp = '\0'; ++ Mkvdir(fullname); ++ *tmp = '/'; ++ } ++ Dirtovd(fullname); ++#else + else fullname = namelist[filenum]; +- ++#endif + + strcpy(fullfname, fullname); + tmp = BaseName(fullname); +@@ -1875,18 +2191,20 @@ + + + /* chop off trailing ".Z", ".z", or ".gz" from displayed basefname, if any */ +- if (strlen(basefname) > (size_t) 2 && +- strcmp(basefname+strlen(basefname)-2,".Z")==0) ++ if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".Z")==0) + basefname[strlen(basefname)-2]='\0'; + else { + #ifdef GUNZIP +- if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".Z")==0) ++ if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".z")==0) + basefname[strlen(basefname)-2]='\0'; +- +- else if (strlen(basefname)>3 && +- strcmp(basefname+strlen(basefname)-3,".gz")==0) ++ else ++ if (strlen(basefname)>3 && strcmp(basefname+strlen(basefname)-3,".gz")==0) + basefname[strlen(basefname)-3]='\0'; +-#endif /* GUNZIP */ ++#endif ++#ifdef BUNZIP2 ++ if (strlen(basefname)>4 && strcmp(basefname+strlen(basefname)-4,".bz2")==0) ++ basefname[strlen(basefname)-4]='\0'; ++#endif + } + + +@@ -1973,6 +2291,9 @@ + + if (strcmp(filename,STDINSTR)==0) { + FILE *fp = NULL; ++#ifndef USE_MKSTEMP ++ int tmpfd; ++#endif + + #ifndef VMS + sprintf(filename,"%s/xvXXXXXX",tmpdir); +@@ -1984,13 +2305,18 @@ + fp = fdopen(mkstemp(filename), "w"); + #else + mktemp(filename); +- fp = fopen(filename, "w"); ++ tmpfd = open(filename,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR); ++ if (tmpfd < 0) FatalError("openPic(): can't create temporary file"); ++ fp = fdopen(tmpfd,"w"); + #endif + if (!fp) FatalError("openPic(): can't write temporary file"); + + clearerr(stdin); + while ( (i=getchar()) != EOF) putc(i,fp); + fclose(fp); ++#ifndef USE_MKSTEMP ++ close(tmpfd); ++#endif + + /* and remove it from list, since we can never reload from stdin */ + if (strcmp(namelist[0], STDINSTR)==0) deleteFromList(0); +@@ -2005,15 +2331,21 @@ + (no pipes or stdin, though it could be compressed) to be loaded */ + filetype = ReadFileType(filename); + ++#ifdef HAVE_MGCSFX ++ if (mgcsfx && filetype == RFT_UNKNOWN){ /* force use MgcSfx */ ++ if(getInputCom() != 0) filetype = RFT_MGCSFX; ++ } ++#endif + +- if (filetype == RFT_COMPRESS) { /* a compressed file. uncompress it */ ++ /* if it's a compressed file, uncompress it: */ ++ if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) { + char tmpname[128]; + + if ( + #ifndef VMS +- UncompressFile(filename, tmpname) ++ UncompressFile(filename, tmpname, filetype) + #else +- UncompressFile(basefname, tmpname) ++ UncompressFile(basefname, tmpname, filetype) + #endif + ) { + +@@ -2029,6 +2361,57 @@ + WaitCursor(); + } + ++#ifdef MACBINARY ++ if (handlemacb && macb_file == True) { ++ char tmpname[128]; ++ ++ if (RemoveMacbinary(filename, tmpname)) { ++ if (strcmp(fullname,filename)!=0) unlink(filename); ++ strcpy(origname, filename); ++ strcpy(filename, tmpname); ++ } ++ else filetype = RFT_ERROR; ++ ++ WaitCursor(); ++ } ++#endif ++ ++#ifdef HAVE_MGCSFX_AUTO ++ if (filetype == RFT_MGCSFX) { ++ char tmpname[128], tmp[256]; ++ char *icom; ++ ++ if ((icom = mgcsfx_auto_input_com(filename)) != NULL) { ++ sprintf(tmpname, "%s/xvmsautoXXXXXX", tmpdir); ++#ifdef USE_MKSTEMP ++ close(mkstemp(tmpname)); ++#else ++ mktemp(tmpname); ++#endif ++ SetISTR(ISTR_INFO, "Converting to known format by MgcSfx auto..."); ++ sprintf(tmp,"%s >%s", icom, tmpname); ++ } ++ else goto ms_auto_no; ++ ++#ifndef VMS ++ if (system(tmp)) ++#else ++ if (!system(tmp)) ++#endif ++ { ++ SetISTR(ISTR_INFO, "Unable to convert '%s' by MgcSfx auto.", ++ BaseName(filename)); ++ Warning(); ++ filetype = RFT_ERROR; ++ goto ms_auto_no; ++ } ++ ++ filetype = ReadFileType(tmpname); ++ if (strcmp(fullname,filename)!=0) unlink(filename); ++ strcpy(filename, tmpname); ++ } ++ms_auto_no: ++#endif /* HAVE_MGCSFX_AUTO */ + + if (filetype == RFT_ERROR) { + char foostr[512]; +@@ -2042,10 +2425,16 @@ + + if (filetype == RFT_UNKNOWN) { + /* view as a text/hex file */ +- TextView(filename); ++#ifdef MACBINARY ++ if (origname[0]) ++ i = TextView(origname); ++ else ++#endif ++ i = TextView(filename); + SetISTR(ISTR_INFO,"'%s' not in a recognized format.", basefname); + /* Warning(); */ +- goto SHOWN_AS_TEXT; ++ if (i) goto SHOWN_AS_TEXT; ++ else goto FAILED; + } + + if (filetype < RFT_ERROR) { +@@ -2073,8 +2462,9 @@ + if (filetype == RFT_XBM && (!i || pinfo.w==0 || pinfo.h==0)) { + /* probably just a '.h' file or something... */ + SetISTR(ISTR_INFO," "); +- TextView(filename); +- goto SHOWN_AS_TEXT; ++ i = TextView(filename); ++ if (i) goto SHOWN_AS_TEXT; ++ else goto FAILED; + } + + if (!i) { +@@ -2209,12 +2599,15 @@ + if (fullname && strcmp(fullname,filename)!=0) unlink(filename); + + +- SetISTR(ISTR_INFO,formatStr); ++ SetISTR(ISTR_INFO, "%s", formatStr); + + SetInfoMode(INF_PART); +- SetISTR(ISTR_FILENAME, "%s", +- (filenum==DFLTPIC || filenum==GRABBED || frompipe) ? +- "<none>" : basefname); ++ if (filenum==DFLTPIC || filenum==GRABBED || frompipe) ++ SetISTR(ISTR_FILENAME, "<none>"); ++ else if (numPages > 1) ++ SetISTR(ISTR_FILENAME, "%s Page %d of %d", basefname, curPage+1, numPages); ++ else ++ SetISTR(ISTR_FILENAME, "%s", basefname); + + SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH); + SetISTR(ISTR_COLOR, ""); +@@ -2424,7 +2817,7 @@ + if (autodither && ncols>0) epicMode = EM_DITH; + + /* if in CM_STDCMAP mode, and *not* in '-wait 0', then autodither */ +- if (colorMapMode == CM_STDCMAP && waitsec != 0) epicMode = EM_DITH; ++ if (colorMapMode == CM_STDCMAP && waitsec != 0.0) epicMode = EM_DITH; + + /* if -smooth or image has been shrunk to fit screen */ + if (autosmooth || (pWIDE >maxWIDE || pHIGH>maxHIGH) +@@ -2510,7 +2903,11 @@ + to generate the correct exposes (particularly with 'BitGravity' turned + on */ + +- if (mainW && !useroot) GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH); ++ /*Brian T. Schellenberger: fix for X 4.2 refresh problem*/ ++ if (mainW && !useroot) { ++ XSync(theDisp, False); ++ GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH); ++ } + + return 1; + +@@ -2542,6 +2939,9 @@ + } + + ++extern byte ZXheader[128]; /* [JCE] Spectrum screen magic number is ++ defined in xvzx.c */ ++ + + /********************************/ + int ReadFileType(fname) +@@ -2554,76 +2954,105 @@ + + FILE *fp; + byte magicno[30]; /* first 30 bytes of file */ +- int rv, n; ++ int rv=RFT_UNKNOWN, n; ++#ifdef MACBINARY ++ int macbin_alrchk = False; ++#endif + + if (!fname) return RFT_ERROR; /* shouldn't happen */ + + fp = xv_fopen(fname, "r"); + if (!fp) return RFT_ERROR; + ++ if (strlen(fname) > 4 && ++ strcasecmp(fname+strlen(fname)-5, ".wbmp")==0) rv = RFT_WBMP; ++ + n = fread(magicno, (size_t) 1, (size_t) 30, fp); + fclose(fp); + +- if (n<30) return RFT_UNKNOWN; /* files less than 30 bytes long... */ ++ if (n<30) return rv; /* files less than 30 bytes long... */ + +- rv = RFT_UNKNOWN; ++#ifdef MACBINARY ++ macb_file = False; ++ while (1) { ++#endif + +- if (strncmp((char *) magicno,"GIF87a", (size_t) 6)==0 || +- strncmp((char *) magicno,"GIF89a", (size_t) 6)==0) rv = RFT_GIF; ++#ifdef HAVE_MGCSFX ++ if (is_mgcsfx(fname, magicno, 30) != 0) rv = RFT_MGCSFX; ++ else ++#endif ++ if (strncmp((char *) magicno,"GIF87a", (size_t) 6)==0 || ++ strncmp((char *) magicno,"GIF89a", (size_t) 6)==0) rv = RFT_GIF; + + else if (strncmp((char *) magicno,"VIEW", (size_t) 4)==0 || +- strncmp((char *) magicno,"WEIV", (size_t) 4)==0) rv = RFT_PM; ++ strncmp((char *) magicno,"WEIV", (size_t) 4)==0) rv = RFT_PM; ++ ++#ifdef HAVE_PIC2 ++ else if (magicno[0]=='P' && magicno[1]=='2' && ++ magicno[2]=='D' && magicno[3]=='T') rv = RFT_PIC2; ++#endif + + else if (magicno[0] == 'P' && magicno[1]>='1' && +- magicno[1]<='6') rv = RFT_PBM; ++ (magicno[1]<='6' || magicno[1]=='8')) rv = RFT_PBM; + + /* note: have to check XPM before XBM, as first 2 chars are the same */ + else if (strncmp((char *) magicno, "/* XPM */", (size_t) 9)==0) rv = RFT_XPM; + + else if (strncmp((char *) magicno,"#define", (size_t) 7)==0 || +- (magicno[0] == '/' && magicno[1] == '*')) rv = RFT_XBM; ++ (magicno[0] == '/' && magicno[1] == '*')) rv = RFT_XBM; + + else if (magicno[0]==0x59 && (magicno[1]&0x7f)==0x26 && +- magicno[2]==0x6a && (magicno[3]&0x7f)==0x15) rv = RFT_SUNRAS; ++ magicno[2]==0x6a && (magicno[3]&0x7f)==0x15) rv = RFT_SUNRAS; + +- else if (magicno[0] == 'B' && magicno[1] == 'M') rv = RFT_BMP; ++ else if (magicno[0] == 'B' && magicno[1] == 'M') rv = RFT_BMP; + +- else if (magicno[0]==0x52 && magicno[1]==0xcc) rv = RFT_UTAHRLE; ++ else if (magicno[0]==0x52 && magicno[1]==0xcc) rv = RFT_UTAHRLE; + + else if ((magicno[0]==0x01 && magicno[1]==0xda) || +- (magicno[0]==0xda && magicno[1]==0x01)) rv = RFT_IRIS; ++ (magicno[0]==0xda && magicno[1]==0x01)) rv = RFT_IRIS; + +- else if (magicno[0]==0x1f && magicno[1]==0x9d) rv = RFT_COMPRESS; ++ else if (magicno[0]==0x1f && magicno[1]==0x9d) rv = RFT_COMPRESS; + + #ifdef GUNZIP +- else if (magicno[0]==0x1f && magicno[1]==0x8b) rv = RFT_COMPRESS; ++ else if (magicno[0]==0x1f && magicno[1]==0x8b) rv = RFT_COMPRESS; + #endif + +- else if (magicno[0]==0x0a && magicno[1] <= 5) rv = RFT_PCX; ++#ifdef BUNZIP2 ++ else if (magicno[0]==0x42 && magicno[1]==0x5a) rv = RFT_BZIP2; ++#endif ++ ++ else if (magicno[0]==0x0a && magicno[1] <= 5) rv = RFT_PCX; + + else if (strncmp((char *) magicno, "FORM", (size_t) 4)==0 && +- strncmp((char *) magicno+8, "ILBM", (size_t) 4)==0) rv = RFT_IFF; ++ strncmp((char *) magicno+8, "ILBM", (size_t) 4)==0) rv = RFT_IFF; + + else if (magicno[0]==0 && magicno[1]==0 && + magicno[2]==2 && magicno[3]==0 && + magicno[4]==0 && magicno[5]==0 && +- magicno[6]==0 && magicno[7]==0) rv = RFT_TARGA; ++ magicno[6]==0 && magicno[7]==0) rv = RFT_TARGA; + + else if (magicno[4]==0x00 && magicno[5]==0x00 && +- magicno[6]==0x00 && magicno[7]==0x07) rv = RFT_XWD; ++ magicno[6]==0x00 && magicno[7]==0x07) rv = RFT_XWD; + + else if (strncmp((char *) magicno,"SIMPLE ", (size_t) 8)==0 && +- magicno[29] == 'T') rv = RFT_FITS; ++ magicno[29] == 'T') rv = RFT_FITS; + ++ /* [JCE] Spectrum screen */ ++ else if (memcmp(magicno, ZXheader, (size_t) 18)==0) rv = RFT_ZX; + + #ifdef HAVE_JPEG + else if (magicno[0]==0xff && magicno[1]==0xd8 && +- magicno[2]==0xff) rv = RFT_JFIF; ++ magicno[2]==0xff) rv = RFT_JFIF; + #endif + + #ifdef HAVE_TIFF + else if ((magicno[0]=='M' && magicno[1]=='M') || +- (magicno[0]=='I' && magicno[1]=='I')) rv = RFT_TIFF; ++ (magicno[0]=='I' && magicno[1]=='I')) rv = RFT_TIFF; ++#endif ++ ++#ifdef HAVE_PNG ++ else if (magicno[0]==0x89 && magicno[1]=='P' && ++ magicno[2]=='N' && magicno[3]=='G') rv = RFT_PNG; + #endif + + #ifdef HAVE_PDS +@@ -2635,11 +3064,59 @@ + rv = RFT_PDSVICAR; + #endif + +-#ifdef GS_PATH ++#ifdef GS_PATH /* Ghostscript handles both PostScript and PDF */ + else if (strncmp((char *) magicno, "%!", (size_t) 2)==0 || +- strncmp((char *) magicno, "\004%!", (size_t) 3)==0) rv = RFT_PS; ++ strncmp((char *) magicno, "\004%!", (size_t) 3)==0 || ++ strncmp((char *) magicno, "%PDF", (size_t) 4)==0) rv = RFT_PS; + #endif + ++#ifdef HAVE_MAG ++ else if (strncmp((char *) magicno,"MAKI02 ", (size_t) 8)==0) rv = RFT_MAG; ++#endif ++ ++#ifdef HAVE_MAKI ++ else if (strncmp((char *) magicno,"MAKI01A ", (size_t) 8)==0 || ++ strncmp((char *) magicno,"MAKI01B ", (size_t) 8)==0) rv = RFT_MAKI; ++#endif ++ ++#ifdef HAVE_PIC ++ else if (magicno[0]=='P' && magicno[1]=='I'&&magicno[2]=='C') rv = RFT_PIC; ++#endif ++ ++#ifdef HAVE_PI ++ else if (magicno[0]=='P' && magicno[1]=='i') rv = RFT_PI; ++#endif ++ ++#ifdef HAVE_HIPS ++ else if (strstr((char *) magicno, "./digest")) rv = RFT_HIPS; ++#endif ++ ++#ifdef HAVE_PCD ++ else if (magicno[0]==0xff && magicno[1]==0xff && ++ magicno[2]==0xff && magicno[3]==0xff) rv = RFT_PCD; ++#endif ++ ++#ifdef MACBINARY ++ /* Now we try to handle MacBinary files, but the method is VERY dirty... */ ++ if (macbin_alrchk == True) { ++ macb_file = True; ++ break; ++ } ++ ++ if (rv != RFT_UNKNOWN) ++ break; ++ ++ /* Skip MACBSIZE and recheck */ ++ macbin_alrchk = True; ++ fp = xv_fopen(fname, "r"); ++ if (!fp) return RFT_ERROR; ++ fseek(fp, MACBSIZE, SEEK_SET); ++ n = fread(magicno, (size_t) 1, (size_t) 30, fp); ++ fclose(fp); ++ ++ if (n<30) return RFT_UNKNOWN; /* files less than 30 bytes long... */ ++ } ++#endif + return rv; + } + +@@ -2652,9 +3129,10 @@ + PICINFO *pinfo; + { + /* if quick is set, we're being called to generate icons, or something +- like that. We should load the image as quickly as possible. Currently, +- this only affects the LoadPS routine, which, if quick is set, only +- generates the page file for the first page of the document */ ++ like that. We should load the image as quickly as possible. Previously, ++ this affected only the LoadPS routine, which, if quick is set, only ++ generates the page file for the first page of the document. Now it ++ also affects PCD, which loads only a thumbnail. */ + + int rv = 0; + +@@ -2665,7 +3143,11 @@ + switch (ftype) { + case RFT_GIF: rv = LoadGIF (fname, pinfo); break; + case RFT_PM: rv = LoadPM (fname, pinfo); break; ++#ifdef HAVE_MGCSFX ++ case RFT_PBM: rv = LoadPBM (fname, pinfo, -1); break; ++#else + case RFT_PBM: rv = LoadPBM (fname, pinfo); break; ++#endif + case RFT_XBM: rv = LoadXBM (fname, pinfo); break; + case RFT_SUNRAS: rv = LoadSunRas(fname, pinfo); break; + case RFT_BMP: rv = LoadBMP (fname, pinfo); break; +@@ -2677,21 +3159,60 @@ + case RFT_XPM: rv = LoadXPM (fname, pinfo); break; + case RFT_XWD: rv = LoadXWD (fname, pinfo); break; + case RFT_FITS: rv = LoadFITS (fname, pinfo, quick); break; ++ case RFT_ZX: rv = LoadZX (fname, pinfo); break; /* [JCE] */ ++ case RFT_WBMP: rv = LoadWBMP (fname, pinfo); break; ++ ++#ifdef HAVE_PCD ++ /* if quick is switched on, use the smallest image size; don't ask the user */ ++ case RFT_PCD: rv = LoadPCD (fname, pinfo, quick ? 0 : PcdSize); break; ++#endif + + #ifdef HAVE_JPEG +- case RFT_JFIF: rv = LoadJFIF (fname, pinfo, quick); break; ++ case RFT_JFIF: rv = LoadJFIF (fname, pinfo, quick); break; + #endif + + #ifdef HAVE_TIFF +- case RFT_TIFF: rv = LoadTIFF (fname, pinfo, quick); break; ++ case RFT_TIFF: rv = LoadTIFF (fname, pinfo, quick); break; ++#endif ++ ++#ifdef HAVE_PNG ++ case RFT_PNG: rv = LoadPNG (fname, pinfo); break; + #endif + + #ifdef HAVE_PDS +- case RFT_PDSVICAR: rv = LoadPDS (fname, pinfo); break; ++ case RFT_PDSVICAR: rv = LoadPDS (fname, pinfo); break; + #endif + + #ifdef GS_PATH +- case RFT_PS: rv = LoadPS (fname, pinfo, quick); break; ++ case RFT_PS: rv = LoadPS (fname, pinfo, quick); break; ++#endif ++ ++#ifdef HAVE_MAG ++ case RFT_MAG: rv = LoadMAG (fname, pinfo); break; ++#endif ++ ++#ifdef HAVE_MAKI ++ case RFT_MAKI: rv = LoadMAKI (fname, pinfo); break; ++#endif ++ ++#ifdef HAVE_PIC ++ case RFT_PIC: rv = LoadPIC (fname, pinfo); break; ++#endif ++ ++#ifdef HAVE_PI ++ case RFT_PI: rv = LoadPi (fname, pinfo); break; ++#endif ++ ++#ifdef HAVE_PIC2 ++ case RFT_PIC2: rv = LoadPIC2 (fname, pinfo, quick); break; ++#endif ++ ++#ifdef HAVE_HIPS ++ case RFT_HIPS: rv = LoadHIPS (fname, pinfo); break; ++#endif ++ ++#ifdef HAVE_MGCSFX ++ case RFT_MGCSFX: rv = LoadMGCSFX (fname, pinfo); break; + #endif + + } +@@ -2700,13 +3221,17 @@ + + + /********************************/ +-int UncompressFile(name, uncompname) ++int UncompressFile(name, uncompname, filetype) + char *name, *uncompname; ++ int filetype; + { + /* returns '1' on success, with name of uncompressed file in uncompname + returns '0' on failure */ + + char namez[128], *fname, buf[512]; ++#ifndef USE_MKSTEMP ++ int tmpfd; ++#endif + + fname = name; + namez[0] = '\0'; +@@ -2746,15 +3271,23 @@ + close(mkstemp(uncompname)); + #else + mktemp(uncompname); ++ tmpfd = open(uncompname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR); ++ if (tmpfd < 0) FatalError("UncompressFile(): can't create temporary file"); ++ close(tmpfd); + #endif + + #ifndef VMS +- sprintf(buf,"%s -c %s >%s", UNCOMPRESS, fname, uncompname); ++ if (filetype == RFT_COMPRESS) ++ sprintf(buf,"%s -c '%s' > '%s'", UNCOMPRESS, fname, uncompname); ++# ifdef BUNZIP2 ++ else if (filetype == RFT_BZIP2) ++ sprintf(buf,"%s -c '%s' > '%s'", BUNZIP2, fname, uncompname); ++# endif + #else /* it IS VMS */ + # ifdef GUNZIP +- sprintf(buf,"%s %s %s", UNCOMPRESS, fname, uncompname); ++ sprintf(buf,"%s '%s' '%s'", UNCOMPRESS, fname, uncompname); + # else +- sprintf(buf,"%s %s", UNCOMPRESS, fname); ++ sprintf(buf,"%s '%s'", UNCOMPRESS, fname); + # endif + #endif + +@@ -2797,6 +3330,62 @@ + } + + ++#ifdef MACBINARY ++/********************************/ ++int RemoveMacbinary(src, dst) ++ char *src, *dst; ++{ ++ char buffer[8192]; /* XXX */ ++ int n, eof; ++#ifndef USE_MKSTEMP ++ int tmpfd; ++#endif ++ FILE *sfp, *dfp; ++ ++ sprintf(dst, "%s/xvmXXXXXX", tmpdir); ++#ifdef USE_MKSTEMP ++ close(mkstemp(dst)); ++#else ++ mktemp(dst); ++ tmpfd = open(dst,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR); ++ if (tmpfd < 0) FatalError("RemoveMacbinary(): can't create temporary file"); ++#endif ++ ++ SetISTR(ISTR_INFO, "Removing MacBinary..."); ++ ++ sfp = xv_fopen(src, "r"); ++#ifdef USE_MKSTEMP ++ dfp = xv_fopen(dst, "w"); ++#else ++ dfp = fdopen(tmpfd, "w"); ++#endif ++ if (!sfp || !dfp) { ++ SetISTR(ISTR_INFO, "Unable to remove a InfoFile header form '%s'.", src); ++ Warning(); ++ return 0; ++ } ++ fseek(sfp, MACBSIZE, SEEK_SET); ++ while ((n = fread(buffer, 1, sizeof(buffer), sfp)) == 8192) /* XXX */ ++ fwrite(buffer, 1, n, dfp); ++ if ((eof = feof(sfp))) ++ fwrite(buffer, 1, n, dfp); ++ fclose(sfp); ++ fflush(dfp); ++ fclose(dfp); ++#ifndef USE_MKSTEMP ++ close(tmpfd); ++#endif ++ if (!eof) { ++ SetISTR(ISTR_INFO, "Unable to remove a InfoFile header form '%s'.", src); ++ Warning(); ++ return 0; ++ } ++ ++ return 1; ++} ++#endif ++ ++ + /********************************/ + void KillPageFiles(bname, numpages) + char *bname; +@@ -2918,6 +3507,9 @@ + + char fullcmd[512], tmpname[64], str[512]; + int i; ++#ifndef USE_MKSTEMP ++ int tmpfd; ++#endif + + if (!cmd || (strlen(cmd) < (size_t) 2)) return 1; + +@@ -2926,6 +3518,9 @@ + close(mkstemp(tmpname)); + #else + mktemp(tmpname); ++ tmpfd = open(tmpname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR); ++ if (tmpfd < 0) FatalError("openPic(): can't create temporary file"); ++ close(tmpfd); + #endif + if (tmpname[0] == '\0') { /* mktemp() or mkstemp() blew up */ + sprintf(str,"Unable to create temporary filename."); +@@ -2966,26 +3561,21 @@ + { + int i; + ++ waitsec = (numnames <= 1)? waitsec_final : waitsec_nonfinal; ++ + if (!numnames) { openPic(DFLTPIC); return; } + + i = 0; +- if (!randomShow) { +- while (numnames>0) { +- if (openPic(0)) return; /* success */ +- else { +- if (polling && !i) +- fprintf(stderr,"%s: POLLING: Waiting for file '%s' \n\tto %s\n", +- cmd, namelist[0], "be created, or whatever..."); +- i = 1; +- } ++ while (numnames>0) { ++ if (openPic(0)) return; /* success */ ++ else { ++ if (polling && !i) ++ fprintf(stderr,"%s: POLLING: Waiting for file '%s' \n\tto %s\n", ++ cmd, namelist[0], "be created, or whatever..."); ++ i = 1; + } + } + +- else { /* pick random first picture */ +- for (i=findRandomPic(); i>=0; i=findRandomPic()) +- if (openPic(i)) return; /* success */ +- } +- + if (numnames>1) FatalError("couldn't open any pictures"); + else Quit(-1); + } +@@ -3014,19 +3604,15 @@ + { + int i; + +- if (!randomShow) { +- if (curname>=0) i = curname+1; +- else if (nList.selected >= 0 && nList.selected < numnames) +- i = nList.selected; +- else i = 0; ++ if (curname>=0) i = curname+1; ++ else if (nList.selected >= 0 && nList.selected < numnames) ++ i = nList.selected; ++ else i = 0; + +- while (i<numnames && !openPic(i)); +- if (i<numnames) return; /* success */ +- } +- else { +- for (i=findRandomPic(); i>=0; i=findRandomPic()) +- if (openPic(i)) return; +- } ++ waitsec = (i == numnames-1)? waitsec_final : waitsec_nonfinal; ++ ++ while (i<numnames && !openPic(i)); ++ if (i<numnames) return; /* success */ + + Quit(0); + } +@@ -3039,25 +3625,21 @@ + + j = loop = 0; + while (1) { +- if (!randomShow) { + +- if (curname>=0) i = curname+1; +- else if (nList.selected >= 0 && nList.selected < numnames) +- i = nList.selected; +- else i = 0; ++ if (curname>=0) i = curname+1; ++ else if (nList.selected >= 0 && nList.selected < numnames) ++ i = nList.selected; ++ else i = 0; + +- if (loop) { i = 0; loop = 0; } ++ if (loop) { i = 0; loop = 0; } + +- while (i<numnames && !openPic(i)); +- if (i<numnames) return; +- } +- else { +- for (i=findRandomPic(); i>=0; i=findRandomPic()) +- if (openPic(i)) return; +- } ++ waitsec = (i == numnames-1)? waitsec_final : waitsec_nonfinal; ++ ++ while (i<numnames && !openPic(i)); ++ if (i<numnames) return; + + loop = 1; /* back to top of list */ +- if (j) break; /* we're in a 'failure loop' */ ++ if (j) break; /* we're in a 'failure loop' */ + j++; + } + +@@ -3090,47 +3672,6 @@ + openPic(LOADPIC); + } + +- +- +- +-/****************/ +-static int findRandomPic() +-/****************/ +-{ +- static byte *loadList; +- static int left_to_load, listLen = -1; +- int k; +- time_t t; +- +- /* picks a random name out of the list, and returns it's index. If there +- are no more names to pick, it returns '-1' and resets itself */ +- +- if (!loadList || numnames!=listLen) { +- if (loadList) free(loadList); +- else { +- time(&t); +- srandom((unsigned int) t); /* seed the random */ +- } +- +- left_to_load = listLen = numnames; +- loadList = (byte *) malloc((size_t) listLen); +- for (k=0; k<listLen; k++) loadList[k] = 0; +- } +- +- if (left_to_load <= 0) { /* we've loaded all the pics */ +- for (k=0; k<listLen; k++) loadList[k] = 0; /* clear flags */ +- left_to_load = listLen; +- return -1; /* 'done' return */ +- } +- +- for (k=abs(random()) % listLen; loadList[k]; k = (k+1) % listLen); +- +- left_to_load--; +- loadList[k] = TRUE; +- +- return k; +-} +- + /****************/ + static void mainLoop() + { +@@ -3144,10 +3685,11 @@ + selected file (or the 0th file, if no selection either), and 'Prev' means + view the one right before the selected file */ + +- openFirstPic(); /* find first displayable picture, exit if none */ ++ /* find first displayable picture, exit if none */ ++ if (!startGrab) openFirstPic(); + + if (!pic) { /* must've opened a text file... display dflt pic */ +- openPic(DFLTPIC); ++ if (!startGrab) openPic(DFLTPIC); + if (mainW && !useroot) RaiseTextWindows(); + } + +@@ -3224,8 +3766,16 @@ + hints.flags = 0; + if ((i&XValue || i&YValue)) hints.flags = USPosition; + +- if (i&XValue && i&XNegative) x = vrWIDE - eWIDE - abs(x); +- if (i&YValue && i&YNegative) y = vrHIGH - eHIGH - abs(y); ++ hints.win_gravity = NorthWestGravity; ++ if (i&XValue && i&XNegative) { ++ hints.win_gravity = NorthEastGravity; ++ x = vrWIDE - (eWIDE + 2 * bwidth) - abs(x); ++ } ++ if (i&YValue && i&YNegative) { ++ hints.win_gravity = (hints.win_gravity == NorthWestGravity) ? ++ SouthWestGravity : SouthEastGravity; ++ y = vrHIGH - (eHIGH + 2 * bwidth) - abs(y); ++ } + + if (x+eWIDE > vrWIDE) x = vrWIDE - eWIDE; /* keep on screen */ + if (y+eHIGH > vrHIGH) y = vrHIGH - eHIGH; +@@ -3245,7 +3795,7 @@ + hints.x = x; hints.y = y; + hints.width = eWIDE; hints.height = eHIGH; + hints.max_width = maxWIDE; hints.max_height = maxHIGH; +- hints.flags |= USSize | PMaxSize; ++ hints.flags |= USSize | PMaxSize | PWinGravity; + + xswa.bit_gravity = StaticGravity; + xswa.background_pixel = bg; +@@ -3294,10 +3844,6 @@ + } + } + +- +- XSetStandardProperties(theDisp,mainW,"","",None,NULL,0,&hints); +- setWinIconNames(name); +- + xwmh.input = True; + xwmh.flags = InputHint; + +@@ -3322,12 +3868,13 @@ + } + } + } +- XSetWMHints(theDisp, mainW, &xwmh); + + classh.res_name = "xv"; + classh.res_class = "XVroot"; +- XSetClassHint(theDisp, mainW, &classh); + ++ XmbSetWMProperties(theDisp, mainW, NULL, NULL, NULL, 0, &hints, &xwmh, ++ &classh); ++ setWinIconNames(name); + + if (nodecor) { /* turn of image window decorations (in MWM) */ + Atom mwm_wm_hints; +@@ -4070,16 +4617,30 @@ + unsigned long nitems, nleft; + byte *data; + +- i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0), +- resAtom, 0L, 1L, False, +- XA_STRING, &actType, &actFormat, &nitems, &nleft, +- (unsigned char **) &data); ++ if (spec_window) { ++ i = XGetWindowProperty(theDisp, spec_window, ++ resAtom, 0L, 1L, False, ++ XA_STRING, &actType, &actFormat, &nitems, &nleft, ++ (unsigned char **) &data); ++ } else { ++ i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0), ++ resAtom, 0L, 1L, False, ++ XA_STRING, &actType, &actFormat, &nitems, &nleft, ++ (unsigned char **) &data); ++ } + if (i==Success && actType==XA_STRING && actFormat==8) { + if (nitems>0 && data) XFree(data); +- i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0), resAtom, 0L, +- (long) ((nleft+4+3)/4), +- False, XA_STRING, &actType, &actFormat, +- &nitems, &nleft, (unsigned char **) &data); ++ if (spec_window) { ++ i = XGetWindowProperty(theDisp, spec_window, resAtom, 0L, ++ (long) ((nleft+4+3)/4), ++ False, XA_STRING, &actType, &actFormat, ++ &nitems, &nleft, (unsigned char **) &data); ++ } else { ++ i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0), resAtom, 0L, ++ (long) ((nleft+4+3)/4), ++ False, XA_STRING, &actType, &actFormat, ++ &nitems, &nleft, (unsigned char **) &data); ++ } + if (i==Success && actType==XA_STRING && actFormat==8 && data) { + def_resource = XrmGetStringDatabase((char *) data); + XFree(data); +diff -ruN xv-3.10a-bugfixes/xv.h xv-3.10a-enhancements/xv.h +--- xv-3.10a-bugfixes/xv.h 2005-04-10 09:37:18.000000000 -0700 ++++ xv-3.10a-enhancements/xv.h 2005-05-01 13:32:10.000000000 -0700 +@@ -14,8 +14,9 @@ + /* GRR orig jumbo enhancements patch: 20000220 */ + /* GRR 1st public jumbo F+E patches: 20040531 */ + /* GRR 2nd public jumbo F+E patches: 20050410 */ +-#define REVDATE "version 3.10a-jumboFix of 20050410" +-#define VERSTR "3.10a-20050410" ++/* GRR 3rd public jumbo F+E patches: 20050501 */ ++#define REVDATE "version 3.10a-jumboFix+Enh of 20050501" ++#define VERSTR "3.10a-20050501" + + /* + * uncomment the following, and modify for your site, but only if you've +@@ -49,6 +50,10 @@ + /* START OF MACHINE-DEPENDENT CONFIGURATION INFO */ + /*************************************************/ + ++ ++#define ENABLE_FIXPIX_SMOOTH /* GRR 19980607 */ ++ ++ + /* Things to make xv more likely to just build, without the user tweaking + the makefile */ + +@@ -67,6 +72,14 @@ + # define SVR4 + #endif + ++#if defined(__sony_news) && defined(bsd43) && !defined(__bsd43) ++# define __bsd43 ++#elif defined(__sony_news) && (defined(SYSTYPE_BSD) || defined(__SYSTYPE_BSD)) && !defined(bsd43) && !defined(__bsd43) ++# define bsd43 ++# define __bsd43 ++#endif ++ ++#include <signal.h> /* for interrupt handling */ + + /* at least on Linux, the following file (1) includes sys/types.h and + * (2) defines __USE_BSD (which was not defined before here), so __linux__ +@@ -78,7 +91,9 @@ + # ifndef _LINUX_LIMITS_H + # include <linux/limits.h> + # endif +-# define USLEEP ++# ifndef USLEEP ++# define USLEEP ++# endif + /* want only one or the other defined, not both: */ + # if !defined(BSDTYPES) && !defined(__USE_BSD) + # define BSDTYPES +@@ -117,6 +132,16 @@ + #endif + + ++#if defined(__sony_news) && defined(__bsd43) ++# include <unistd.h> ++#endif ++ ++ ++#if defined(__FreeBSD__) ++# include <sys/param.h> ++#endif ++ ++ + /* include files */ + #include <stdio.h> + #include <math.h> +@@ -132,9 +157,11 @@ + + #ifndef VMS + # include <errno.h> +- extern int errno; /* SHOULD be in errno.h, but often isn't */ +-# if !defined(__NetBSD__) && !(defined(__linux__) && defined(__USE_BSD)) +- extern char *sys_errlist[]; /* this too... */ ++# ifndef __NetBSD__ ++# if !(defined __GLIBC__ && __GLIBC__ >= 2) ++ extern int errno; /* SHOULD be in errno.h, but often isn't */ ++ extern char *sys_errlist[]; /* this too... */ ++# endif + # endif + #endif + +@@ -203,9 +230,10 @@ + #include <X11/Xatom.h> + #include <X11/Xmd.h> + ++#ifdef TV_L10N ++# include <X11/Xlocale.h> ++#endif + +-#undef SIGCHLD /* defined in both Xos.h and signal.h */ +-#include <signal.h> /* for interrupt handling */ + + #include <sys/types.h> + +@@ -316,7 +344,9 @@ + # endif + #endif + +- ++#ifndef S_IRWUSR ++# define S_IRWUSR (S_IRUSR|__S_IWRITE) ++#endif + + #ifndef MAXPATHLEN + # define MAXPATHLEN 256 +@@ -343,13 +373,36 @@ + #endif + + +-/* GRR 20040430: This is new and still only partially implemented. No doubt +- * there are many other systems that have mkstemp() (SUSv3), +- * but let's start small... */ +-#if defined(__linux__) || defined(__OpenBSD__) +-# define USE_MKSTEMP /* use 'mkstemp()' instead of 'mktemp()' */ ++/* GRR 20040430: This is new and still not fully deployed. No doubt there ++ * are other systems that have mkstemp() (SUSv3); we can add ++ * them later. */ ++#ifndef VMS /* VMS hates multi-line definitions */ ++# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ ++ defined(__bsdi__) ++# ifndef USE_MKSTEMP ++# define USE_MKSTEMP /* use 'mkstemp()' instead of 'mktemp()' */ ++# endif /* >> SECURITY ISSUE << */ ++# endif ++#endif ++ ++ ++/* GRR 20040503: This is new and so far tested only under Linux. But it ++ * allows -wait to work with subsecond values as long as ++ * times() exists and clock_t is a long int (latter matters ++ * only if/when clocks wrap, which for Linux is multiples of ++ * 497.11 days since the last reboot). */ ++#if defined(__linux__) ++# define USE_TICKS /* use times()/Timer(), not time()/sleep() */ ++# include <limits.h> /* LONG_MAX (really want CLOCK_T_MAX) */ ++# include <sys/times.h> /* times() */ ++# ifndef CLK_TCK /* can be undefined in strict-ANSI mode */ ++# define CLK_TCK CLOCKS_PER_SEC /* claimed to be same thing in time.h */ ++# endif + #endif + ++#if (defined(SYSV) || defined(SVR4) || defined(linux)) && !defined(USE_GETCWD) ++# define USE_GETCWD ++#endif + + /*****************************/ + /* END OF CONFIGURATION INFO */ +@@ -363,17 +416,21 @@ + # define HAVE_TIFF + #endif + ++#ifdef DOPNG ++# define HAVE_PNG ++#endif ++ + #ifdef DOPDS + # define HAVE_PDS + #endif + + + +-#define PROGNAME "xv" /* used in resource database */ ++#define PROGNAME "xv" /* used in resource database */ + +-#define MAXNAMES 4096 /* max # of files in ctrlW list */ ++#define MAXNAMES 32768 /* max # of files in ctrlW list */ + +-#define MAXBRWIN 4 /* max # of vis browser windows */ ++#define MAXBRWIN 16 /* max # of vis browser windows */ + + /* strings in the INFOBOX (used in SetISTR and GetISTR) */ + #define NISTR 10 /* number of ISTRs */ +@@ -494,24 +551,80 @@ + #define F_TIFINC 0 + #endif + ++#ifdef HAVE_PNG ++#define F_PNGINC 1 ++#else ++#define F_PNGINC 0 ++#endif ++ ++#ifdef HAVE_MAG ++# define F_MAGINC 1 ++#else ++# define F_MAGINC 0 ++#endif ++ ++#ifdef HAVE_PIC ++# define F_PICINC 1 ++#else ++# define F_PICINC 0 ++#endif ++ ++#ifdef HAVE_MAKI ++# define F_MAKINC 1 ++#else ++# define F_MAKINC 0 ++#endif ++ ++#ifdef HAVE_PI ++# define F_PAIINC 1 ++#else ++# define F_PAIINC 0 ++#endif ++ ++#ifdef HAVE_PIC2 ++# define F_PC2INC 1 ++#else ++# define F_PC2INC 0 ++#endif ++ ++#ifdef HAVE_MGCSFX ++# define F_MGCSFXINC 1 ++#else ++# define F_MGCSFXINC 0 ++#endif ++ ++#ifdef MACBINARY ++# define MACBSIZE 128 ++#endif + + #define F_GIF 0 + #define F_JPEG ( 0 + F_JPGINC) + #define F_TIFF ( 0 + F_JPGINC + F_TIFINC) +-#define F_PS ( 1 + F_JPGINC + F_TIFINC) +-#define F_PBMRAW ( 2 + F_JPGINC + F_TIFINC) +-#define F_PBMASCII ( 3 + F_JPGINC + F_TIFINC) +-#define F_XBM ( 4 + F_JPGINC + F_TIFINC) +-#define F_XPM ( 5 + F_JPGINC + F_TIFINC) +-#define F_BMP ( 6 + F_JPGINC + F_TIFINC) +-#define F_SUNRAS ( 7 + F_JPGINC + F_TIFINC) +-#define F_IRIS ( 8 + F_JPGINC + F_TIFINC) +-#define F_TARGA ( 9 + F_JPGINC + F_TIFINC) +-#define F_FITS (10 + F_JPGINC + F_TIFINC) +-#define F_PM (11 + F_JPGINC + F_TIFINC) +-#define F_DELIM1 (12 + F_JPGINC + F_TIFINC) /* ----- */ +-#define F_FILELIST (13 + F_JPGINC + F_TIFINC) +-#define F_MAXFMTS (14 + F_JPGINC + F_TIFINC) /* 15, normally */ ++#define F_PNG ( 0 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_PS ( 1 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_PBMRAW ( 2 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_PBMASCII ( 3 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_XBM ( 4 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_XPM ( 5 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_BMP ( 6 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_SUNRAS ( 7 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_IRIS ( 8 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_TARGA ( 9 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_FITS (10 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_PM (11 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define F_ZX (12 + F_JPGINC + F_TIFINC + F_PNGINC) /* [JCE] */ ++#define F_WBMP (13 + F_JPGINC + F_TIFINC + F_PNGINC) ++#define JP_EXT_F (F_WBMP) ++#define F_MAG (JP_EXT_F + F_MAGINC) ++#define F_PIC (JP_EXT_F + F_MAGINC + F_PICINC) ++#define F_MAKI (JP_EXT_F + F_MAGINC + F_PICINC + F_MAKINC) ++#define F_PI (JP_EXT_F + F_MAGINC + F_PICINC + F_MAKINC + F_PAIINC) ++#define F_PIC2 (JP_EXT_F + F_MAGINC + F_PICINC + F_MAKINC + F_PAIINC + F_PC2INC) ++#define F_MGCSFX (JP_EXT_F + F_MAGINC + F_PICINC + F_MAKINC + F_PAIINC + F_PC2INC + F_MGCSFXINC) ++#define JP_EXT_F_END (F_MGCSFX) ++#define F_DELIM1 (JP_EXT_F_END + 1) /* ----- */ ++#define F_FILELIST (JP_EXT_F_END + 2) ++#define F_MAXFMTS (JP_EXT_F_END + 3) /* 23, normally */ + + + +@@ -541,6 +654,19 @@ + #define RFT_XPM 17 + #define RFT_XWD 18 + #define RFT_FITS 19 ++#define RFT_PNG 20 ++#define RFT_ZX 21 /* [JCE] */ ++#define RFT_WBMP 22 ++#define RFT_PCD 23 ++#define RFT_HIPS 24 ++#define RFT_BZIP2 25 ++#define JP_EXT_RFT (RFT_BZIP2) ++#define RFT_MAG (JP_EXT_RFT + 1) ++#define RFT_MAKI (JP_EXT_RFT + 2) ++#define RFT_PIC (JP_EXT_RFT + 3) ++#define RFT_PI (JP_EXT_RFT + 4) ++#define RFT_PIC2 (JP_EXT_RFT + 5) ++#define RFT_MGCSFX (JP_EXT_RFT + 6) + + /* definitions for page up/down, arrow up/down list control */ + #define LS_PAGEUP 0 +@@ -599,7 +725,8 @@ + #define RM_CBRICK 7 /* centered on a 'brick' bg */ + #define RM_ECENTER 8 /* symmetrical tiled */ + #define RM_ECMIRR 9 /* symmetrical mirror tiled */ +-#define RM_MAX RM_ECMIRR ++#define RM_UPLEFT 10 /* just in upper left corner */ ++#define RM_MAX RM_UPLEFT + + + /* values of colorMapMode */ +@@ -649,7 +776,8 @@ + #define RMB_CBRICK 8 + #define RMB_ECENTER 9 + #define RMB_ECMIRR 10 +-#define RMB_MAX 11 ++#define RMB_UPLEFT 11 ++#define RMB_MAX 12 + + + /* indicies into conv24MB */ +@@ -784,9 +912,9 @@ + int len; /* length of major axis */ + int vert; /* true if vertical, else horizontal */ + int active; /* true if scroll bar can do anything*/ +- int min,max; /* min/max values 'pos' can take */ +- int val; /* 'value' of scrollbar */ +- int page; /* amt val change on pageup/pagedown */ ++ double min,max; /* min/max values 'pos' can take */ ++ double val; /* 'value' of scrollbar */ ++ double page; /* amt val change on pageup/pagedown */ + int tpos; /* thumb pos. (pixels from tmin) */ + int tmin,tmax; /* min/max thumb offsets (from 0,0) */ + int tsize; /* size of thumb (in pixels) */ +@@ -801,9 +929,10 @@ + typedef struct { Window win; /* window ID */ + int x,y,w,h; /* window coords in parent */ + int active; /* true if can do anything*/ +- int min,max; /* min/max values 'pos' can take */ +- int val; /* 'value' of dial */ +- int page; /* amt val change on pageup/pagedown */ ++ double min,max; /* min/max values 'pos' can take */ ++ double val; /* 'value' of dial */ ++ double inc; /* amt val change on up/down */ ++ double page; /* amt val change on pageup/pagedown */ + char *title; /* title for this guage */ + char *units; /* string appended to value */ + u_long fg,bg,hi,lo; /* colors */ +@@ -971,15 +1100,19 @@ + WHERE unsigned int ncells, dispWIDE, dispHIGH, dispDEEP; + WHERE unsigned int vrWIDE, vrHIGH, maxWIDE, maxHIGH; + WHERE Colormap theCmap, LocalCmap; +-WHERE Window rootW, mainW, vrootW; ++WHERE Window spec_window, rootW, mainW, vrootW; + WHERE GC theGC; + WHERE u_long black, white, fg, bg, infofg, infobg; + WHERE u_long hicol, locol; + WHERE u_long blkRGB, whtRGB; + WHERE Font mfont, monofont; + WHERE XFontStruct *mfinfo, *monofinfo; ++#ifdef TV_L10N ++WHERE XFontSet monofset; ++WHERE XFontSetExtents *monofsetinfo; ++#endif + WHERE Visual *theVisual; +-WHERE Cursor arrow, cross, tcross, zoom, inviso; ++WHERE Cursor arrow, cross, tcross, zoom, inviso, tlcorner; + WHERE Pixmap iconPix, iconmask; + WHERE Pixmap riconPix, riconmask; + WHERE int showzoomcursor; +@@ -996,6 +1129,10 @@ + WHERE int picType; /* CONV24_8BIT,CONV24_24BIT,etc.*/ + WHERE char *picComments; /* text comments on current pic */ + ++#ifdef TV_L10N ++WHERE int xlocale; /* true if Xlib supports locale */ ++#endif ++ + WHERE int numPages, curPage; /* for multi-page files */ + WHERE char pageBaseName[64]; /* basename for multi-page files */ + +@@ -1029,6 +1166,23 @@ + WHERE unsigned long cols[256]; /* maps pic pixel values to X pixel vals */ + WHERE int fc2pcol[256]; /* maps freecols into pic pixel values */ + WHERE int numcols; /* # of desired colors in picture */ ++#ifdef MACBINARY ++WHERE char macb_file; /* True if this file type is MacBinary */ ++WHERE int handlemacb; /* True if we want to handle MacBinary */ ++#endif ++#if defined(HAVE_PIC) || defined(HAVE_PIC2) ++WHERE int nopicadjust; /* True if we don't want to adjust aspect */ ++#endif ++#ifdef HAVE_PIC2 ++WHERE int pic2split; /* True if we want to split multiblocks */ ++#endif ++#ifdef VS_ADJUST ++WHERE int vsadjust; /* True if we want to adjust aspect of icons */ ++#endif ++#ifdef HAVE_MGCSFX ++WHERE int mgcsfx; /* True if we want to force use MgcSfx */ ++WHERE int nomgcsfx; /* True if we don't want to use MgcSfx */ ++#endif + + /* Std Cmap stuff */ + WHERE byte stdr[256], stdg[256], stdb[256]; /* std 3/3/2 cmap */ +@@ -1083,42 +1237,47 @@ + noFreeCols, /* don't free colors when loading new pic */ + autoquit, /* quit in '-root' or when click on win */ + xerrcode, /* errorcode of last X error */ +- grabDelay; /* # of seconds to sleep at start of Grab */ ++ grabDelay, /* # of seconds to sleep at start of Grab */ ++ startGrab; /* start immediate grab ? */ + + WHERE int state824; /* displays warning when going 8->24 */ + + WHERE float defaspect, /* default aspect ratio to use */ + normaspect; /* normal aspect ratio of this picture */ + +-WHERE unsigned long rootbg, rootfg; /* fg/bg for root border */ +-WHERE int waitsec; /* secs btwn pics. -1=wait for event */ +-WHERE int waitloop; /* loop at end of slide show? */ +-WHERE int automax; /* maximize pic on open */ +-WHERE int rootMode; /* mode used for -root images */ ++WHERE u_long rootbg, rootfg; /* fg/bg for root border */ ++WHERE u_short imagebgR; ++WHERE u_short imagebgG; /* GRR 19980308: bg for transpar. images */ ++WHERE u_short imagebgB; ++WHERE int have_imagebg; ++WHERE double waitsec; /* secs btwn pics. -1.0=wait for event */ ++WHERE int waitloop; /* loop at end of slide show? */ ++WHERE int automax; /* maximize pic on open */ ++WHERE int rootMode; /* mode used for -root images */ + +-WHERE int nostat; /* if true, don't stat() in LdCurDir */ ++WHERE int nostat; /* if true, don't stat() in LdCurDir */ + +-WHERE int ctrlColor; /* whether or not to use colored butts */ ++WHERE int ctrlColor; /* whether or not to use colored butts */ + +-WHERE char *def_str; /* used by rd_*() routines */ ++WHERE char *def_str; /* used by rd_*() routines */ + WHERE int def_int; +-WHERE char *tmpdir; /* equal to "/tmp" or $TMPDIR env var */ +-WHERE Pixmap gray25Tile, /* used for 3d effect on 1-bit disp's */ ++WHERE char *tmpdir; /* equal to "/tmp" or $TMPDIR env var */ ++WHERE Pixmap gray25Tile, /* used for 3d effect on 1-bit disp's */ + gray50Tile; +-WHERE int autoDelete; /* delete cmd-line files on exit? */ ++WHERE int autoDelete; /* delete cmd-line files on exit? */ + + #define PRINTCMDLEN 256 + WHERE char printCmd[PRINTCMDLEN]; + + /* stuff used for 'info' box */ + WHERE Window infoW; +-WHERE int infoUp; /* boolean: whether infobox is visible */ ++WHERE int infoUp; /* boolean: whether infobox is visible */ + WHERE int infoMode; + + + /* stuff used for 'ctrl' box */ + WHERE Window ctrlW; +-WHERE int ctrlUp; /* boolean: whether ctrlbox is visible */ ++WHERE int ctrlUp; /* boolean: whether ctrlbox is visible */ + WHERE char *namelist[MAXNAMES]; /* list of file names from argv */ + WHERE char *origlist[MAXNAMES]; /* only names from argv (autoDelete)*/ + WHERE int orignumnames; +@@ -1157,25 +1316,30 @@ + + + /* stuff used for 'browse' box */ +-WHERE int anyBrowUp; /* whether *any* browser visible */ ++WHERE int anyBrowUp; /* whether *any* browser visible */ + + /* stuff used for textview windows */ +-WHERE int anyTextUp; /* are any text windows visible? */ +-WHERE int commentUp; /* comment window up? */ ++WHERE int anyTextUp; /* are any text windows visible? */ ++WHERE int commentUp; /* comment window up? */ + + /* stuff used for xvcut.c */ +-WHERE int forceClipFile; /* don't use property clipboard */ +-WHERE int clearR, clearG, clearB; /* clear color in 24-bit mode */ ++WHERE int forceClipFile; /* don't use property clipboard */ ++WHERE int clearR, clearG, clearB; /* clear color in 24-bit mode */ + + + /* stuff used for 'ps' box */ + WHERE Window psW; +-WHERE int psUp; /* is psW mapped, or what? */ ++WHERE int psUp; /* is psW mapped, or what? */ + WHERE CBUTT encapsCB, pscompCB; + WHERE char *gsDev, *gsGeomStr; + WHERE int gsRes; + + ++/* stuff used for 'pcd' box */ ++WHERE Window pcdW; ++WHERE int pcdUp; /* is pcdW mapped, or what? */ ++ ++ + #ifdef HAVE_JPEG + /* stuff used for 'jpeg' box */ + WHERE Window jpegW; +@@ -1190,6 +1354,91 @@ + #endif + + ++#ifdef HAVE_PNG ++/* stuff used for 'png' box */ ++WHERE Window pngW; ++WHERE int pngUp; /* is pngW mapped, or what? */ ++#endif ++ ++ ++#ifdef ENABLE_FIXPIX_SMOOTH ++WHERE int do_fixpix_smooth; /* GRR 19980607: runtime FS dithering */ ++#endif ++ ++#ifdef HAVE_PIC2 ++/* stuff used for 'pic2' box */ ++WHERE Window pic2W; ++WHERE int pic2Up; /* is pic2W mapped, or what? */ ++#endif /* HAVE_PIC2 */ ++ ++#ifdef HAVE_PCD ++/* stuff used for 'pcd' box */ ++WHERE Window pcdW; ++WHERE int pcdUp; /* is pcdW mapped, or what? */ ++#endif /* HAVE_PCD */ ++ ++#ifdef HAVE_MGCSFX ++/* stuff used for 'mgcsfx' box */ ++WHERE Window mgcsfxW; ++WHERE Window mgcsfxNameW; ++WHERE int mgcsfxUp; /* is mgcsfxW mapped, or what? */ ++#endif /* HAVE_MGCSFX */ ++ ++#ifdef TV_L10N ++/* stuff used for TextViewer Japanization */ ++# define LOCALE_USASCII 0 ++# define LOCALE_EUCJ 1 ++# define LOCALE_JIS 2 ++# define LOCALE_MSCODE 3 ++ ++# ifndef LOCALE_DEFAULT ++# define LOCALE_DEFAULT 0 ++# endif /* !LOCALE_DEFAULT */ ++ ++# ifndef MAIN ++ extern char *localeList[]; ++# else ++# ifndef LOCALE_NAME_EUC ++# ifndef X_LOCALE ++# if defined(__FreeBSD__) ++ char *localeList[] = {"", "ja_JP.EUC", "none", "none"}; ++# elif defined(__linux__) ++ char *localeList[] = {"", "ja_JP.eucJP", "none", "ja_JP.SJIS"}; ++# elif defined(__sun) || defined(sun) ++ char *localeList[] = {"", "ja", "none", "none"}; ++# elif defined(__sgi) /* sgi, __sgi, __sgi__ (gcc) */ ++ char *localeList[] = {"", "ja_JP.EUC", "none", "none"}; ++# elif defined(sony_news) ++ char *localeList[] = {"", "ja_JP.EUC", "none", "ja_JP.SJIS"}; ++# elif defined(nec) ++ char *localeList[] = {"", "japan", "none", "none"}; ++# elif defined(__hpux) ++ char *localeList[] = {"", "japanese.euc", "none", "japanese"}; ++# elif defined(__osf__) ++ char *localeList[] = {"", "ja_JP.deckanji", "none", "ja_JP.SJIS"}; ++# elif defined(_AIX) ++ char *localeList[] = {"", "ja_JP", "none", "Ja_JP" }; ++# elif defined(__bsdi) ++ char *localeList[] = {"", "Japanese-EUC", "none", "none" }; ++# else ++ char *localeList[] = {"", "ja_JP.EUC", "ja_JP.JIS", "ja_JP.SJIS"}; ++# endif ++# else ++# if (XlibSpecificationRelease > 5) ++ char *localeList[] = {"", "ja_JP.eucJP", "ja_JP.JIS7", ++ "ja_JP.SJIS"}; ++# else ++ char *localeList[] = {"", "ja_JP.ujis", "ja_JP.jis7", ++ "ja_JP.mscode"}; ++# endif ++# endif /* X_LOCALE */ ++# else ++ char *localeList[] = {"", LOCALE_NAME_EUC, ++ LOCALE_NAME_JIS, LOCALE_NAME_MSCODE}; ++# endif /* LOCALE_NAME_EUC */ ++# endif /* MAIN */ ++#endif /* TV_L10N */ ++ + #undef WHERE + + +@@ -1199,8 +1448,11 @@ + /****************************** XV.C ****************************/ + int ReadFileType PARM((char *)); + int ReadPicFile PARM((char *, int, PICINFO *, int)); +-int UncompressFile PARM((char *, char *)); ++int UncompressFile PARM((char *, char *, int)); + void KillPageFiles PARM((char *, int)); ++#ifdef MACBINARY ++int RemoveMacbinary PARM((char *, char *)); ++#endif + + void NewPicGetColors PARM((int, int)); + void FixAspect PARM((int, int *, int *)); +@@ -1429,6 +1681,9 @@ + int CheckPoll PARM((int)); + void DIRDeletedFile PARM((char *)); + void DIRCreatedFile PARM((char *)); ++FILE *pic2_OpenOutFile PARM((char *, int *)); ++void pic2_KillNullFile PARM((FILE *)); ++int OpenOutFileDesc PARM((char *)); + + + /*************************** XVBROWSE.C ************************/ +@@ -1448,7 +1703,7 @@ + + /*************************** XVTEXT.C ************************/ + void CreateTextWins PARM((char *, char *)); +-void TextView PARM((char *)); ++int TextView PARM((char *)); + void OpenTextView PARM((char *, int, char *, int)); + + void OpenCommentText PARM((void)); +@@ -1466,6 +1721,8 @@ + int TextCheckEvent PARM((XEvent *, int *, int *)); + int TextDelWin PARM((Window)); + ++int CharsetCheckEvent PARM((XEvent *)); ++int CharsetDelWin PARM((Window)); + + + /**************************** XVGAM.C **************************/ +@@ -1502,12 +1759,12 @@ + + + /*************************** XVDIAL.C ***************************/ +-void DCreate PARM((DIAL *, Window, int, int, int, int, int, +- int, int, int, u_long, u_long, u_long, +- u_long, char *, char *)); ++void DCreate PARM((DIAL *, Window, int, int, int, int, double, ++ double, double, double, double, u_long, ++ u_long, u_long, u_long, char *, char *)); + +-void DSetRange PARM((DIAL *, int, int, int, int)); +-void DSetVal PARM((DIAL *, int)); ++void DSetRange PARM((DIAL *, double,double,double,double,double)); ++void DSetVal PARM((DIAL *, double)); + void DSetActive PARM((DIAL *, int)); + void DRedraw PARM((DIAL *)); + int DTrack PARM((DIAL *, int, int)); +@@ -1585,7 +1842,11 @@ + byte *, byte *, int, int, char *)); + + /**************************** XVPBM.C ***************************/ ++#ifdef HAVE_MGCSFX ++int LoadPBM PARM((char *, PICINFO *, int)); ++#else + int LoadPBM PARM((char *, PICINFO *)); ++#endif + int WritePBM PARM((FILE *, byte *, int, int, int, byte *, + byte *, byte *, int, int, int, char *)); + +@@ -1604,6 +1865,11 @@ + int WriteBMP PARM((FILE *, byte *, int, int, int, byte *, + byte *, byte *, int, int)); + ++/**************************** XVWBMP.C ***************************/ ++int LoadWBMP PARM((char *, PICINFO *)); ++int WriteWBMP PARM((FILE *, byte *, int, int, int, byte *, ++ byte *, byte *, int, int)); ++ + /**************************** XVRLE.C ***************************/ + int LoadRLE PARM((char *, PICINFO *)); + +@@ -1642,6 +1908,7 @@ + void JPEGDialog PARM((int)); + int JPEGCheckEvent PARM((XEvent *)); + void JPEGSaveParams PARM((char *, int)); ++void VersionInfoJPEG PARM((void)); /* GRR 19980605 */ + + /**************************** XVTIFF.C ***************************/ + int LoadTIFF PARM((char *, PICINFO *, int)); +@@ -1649,6 +1916,15 @@ + void TIFFDialog PARM((int)); + int TIFFCheckEvent PARM((XEvent *)); + void TIFFSaveParams PARM((char *, int)); ++void VersionInfoTIFF PARM((void)); /* GRR 19980605 */ ++ ++/**************************** XVPNG.C ***************************/ ++int LoadPNG PARM((char *, PICINFO *)); ++void CreatePNGW PARM((void)); ++void PNGDialog PARM((int)); ++int PNGCheckEvent PARM((XEvent *)); ++void PNGSaveParams PARM((char *, int)); ++void VersionInfoPNG PARM((void)); /* GRR 19980605 */ + + /**************************** XVPDS.C ***************************/ + int LoadPDS PARM((char *, PICINFO *)); +@@ -1661,6 +1937,87 @@ + void PSResize PARM((void)); + int LoadPS PARM((char *, PICINFO *, int)); + ++/************************ [JCE] XVZX.C ***************************/ ++ ++int LoadZX PARM((char *, PICINFO *)); ++int WriteZX PARM((FILE *, byte *, int, int, int, byte *, ++ byte *, byte *, int, int, char *)); ++ ++/**************************** XVPCD.C ***************************/ ++int LoadPCD PARM((char *, PICINFO *, int)); ++void CreatePCDW PARM((void)); ++void PCDDialog PARM((int)); ++int PCDCheckEvent PARM((XEvent *)); ++void PCDSetParamOptions PARM((char *)); ++ ++/*************************** XVMAG.C ***************************/ ++int LoadMAG PARM((char *, PICINFO *)); ++int WriteMAG PARM((FILE *, byte *, int, int, int, ++ byte *, byte *, byte *, int, int, char *)); ++ ++/*************************** XVMAKI.C ***************************/ ++int LoadMAKI PARM((char *, PICINFO *)); ++int WriteMAKI PARM((FILE *, byte *, int, int, int, ++ byte *, byte *, byte *, int, int)); ++ ++/*************************** XVPIC.C ***************************/ ++int LoadPIC PARM((char *, PICINFO *)); ++int WritePIC PARM((FILE *, byte *, int, int, int, ++ byte *, byte *, byte *, int, int, char *)); ++ ++/*************************** XVPI.C ***************************/ ++int LoadPi PARM((char *, PICINFO *)); ++int WritePi PARM((FILE *, byte *, int, int, int, ++ byte *, byte *, byte *, int, int, char *)); ++ ++/*************************** XVPIC2.C ***************************/ ++int LoadPIC2 PARM((char *, PICINFO *, int)); ++void CreatePIC2W PARM((void)); ++void PIC2Dialog PARM((int)); ++int PIC2CheckEvent PARM((XEvent *)); ++int PIC2SetParamOptions PARM((char *)); ++ ++/**************************** XVPCD.C ***************************/ ++int LoadPCD PARM((char *, PICINFO *,int)); ++void CreatePCDW PARM((void)); ++void PCDDialog PARM((int)); ++int PCDCheckEvent PARM((XEvent *)); ++void PCDSetParamOptions PARM((char *)); ++ ++/**************************** XVHIPS.C ***************************/ ++int LoadHIPS PARM((char *, PICINFO *)); ++ ++/*************************** XVMGCSFX.C ***************************/ ++int is_mgcsfx PARM((char *, unsigned char *, int)); ++char *mgcsfx_auto_input_com PARM((char *)); ++int LoadMGCSFX PARM((char *, PICINFO *)); ++void CreateMGCSFXW PARM((void)); ++void MGCSFXDialog PARM((int)); ++int MGCSFXCheckEvent PARM((XEvent *)); ++int MGCSFXSaveParams PARM((char *, int)); ++ ++int getInputCom PARM((void)); ++int getOutputCom PARM((void)); ++ ++/**************************** XVVD.C ****************************/ ++void Vdinit PARM((void)); ++void Vdsettle PARM((void)); ++int Chvdir PARM((char *)); ++void Dirtovd PARM((char *)); ++void Vdtodir PARM((char *)); ++void Dirtosubst PARM((char *)); ++int Mkvdir PARM((char *)); ++void Mkvdir_force PARM((char *)); ++int Rmvdir PARM((char *)); ++int Movevdir PARM((char *, char *)); ++int Isarchive PARM((char *)); ++int Isvdir PARM((char *)); ++void vd_HUPhandler PARM((void)); ++void vd_handler PARM((int)); ++int vd_Xhandler PARM((Display *, XErrorEvent *)); ++int vd_XIOhandler PARM((Display *)); ++void vd_handler_setup PARM((void)); ++ + /*************************** XVPOPUP.C ***************************/ + void CenterMapWindow PARM((Window, int, int, int, int)); + int PopUp PARM((char *, char **, int)); +@@ -1714,3 +2071,13 @@ + void CoordP2E PARM((int, int, int *, int *)); + void CoordE2P PARM((int, int, int *, int *)); + ++#if defined(__mips) && defined(__SYSTYPE_BSD43) ++# define strstr(A,B) pds_strstr((A),(B)) ++# undef S_IFIFO ++#endif /* !mips_bsd */ ++ ++#ifndef SEEK_SET ++# define SEEK_SET 0 ++# define SEEK_CUR 1 ++# define SEEK_END 2 ++#endif +diff -ruN xv-3.10a-bugfixes/xv_mgcsfx.sample xv-3.10a-enhancements/xv_mgcsfx.sample +--- xv-3.10a-bugfixes/xv_mgcsfx.sample 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xv_mgcsfx.sample 2005-04-17 14:04:22.000000000 -0700 +@@ -0,0 +1,125 @@ ++#/* ++# Configuration file for XV with recognition of 'Magic and Suffix' ++# ++# ++# $Id: xv_mgcsfx.sample,v 1.11 95/10/03 17:00:05 tin329 Exp Locker: tin329 $ ++# ++# Author: Tetsuya INOUE <tin329@chino.it.okayama-u.ac.jp> ++# ++# ++# MgcSfx definition should write in one line. ++# Format: ++# <desc>:<ms type>:<ofs>:<magic>:<suffix>:<in it>:<in c>:<out it>:<out c> ++# If you decide to not use preprocessor, comment style is allowed. ++# # <comment> ++# ++# <desc> Description of your recognized image format. ++# <ms type> Type ID for recognition. (You should use 'magic'.) ++# * magic Data of string style. ++# `\' escape for special characters: ++# \b \f \n \r \t \v \\ \' \" \a \? ++# \0 ...\377 octal value ++# \x0 ...\xff hexadecimal value ++# * suffix Suffix of file name. ++# This type check <suffix> instead ++# of <magic>. ++# * [b|l]eint16 2 byte integer of [big|little] endian. ++# * [b|l]eint32 4 byte integer of [big|little] endian. ++# <ofs> Offset of magic number in the target image file. ++# <magic> Data(magic number) of <ms type> to match at <ofs>. ++# <suffix> Suffix of filename with '.'start. ++# ++# <in it> Input image format type (output from <in c>). ++# * PNM (PPM, PGM, PBM) ++# * AUTO Recognized by xv management, and load. ++# This is different from others, because ++# this write file to temporary. ++# <out it> Output image format type (input to <out c>). ++# * PNM_RAW (PPM_RAW, PGM_RAW, PBM_RAW) ++# * PNM_ASCII (PPM_ASCII, PGM_ASCII, PBM_ASCII) ++# ++# <in c> Command to get the input image. ++# * Command mast read stdin or file(specified by ++# argument), and write to stdout. ++# * Use %s to represent the file name. Without %s, ++# get file on stdin. ++# <out c> Command to put the output image. ++# * Command mast read stdin and write to stdout. ++# ++# <comment> Any message. ++#*/ ++ ++#/*############################################################################ ++# ++# definition of the rule with Magic and Suffix ++# ++#*/ ++ ++# /* Canon View Station Image Format */ ++ViewStation(std):magic:0:VsStdImf V0.2:.vs:PNM:VStopnm %s:PNM_RAW:pnmtoVS ++ViewStation(obj):magic:0:VsObjFormat V1.0:.vs:PNM:VSobjtopnm -:PNM_RAW:pnmtoVSobj ++ ++# /* CERN httpd cache */ ++# /* unchc skip header of CERN httpd cache file, and write data to stdout. */ ++CERN httpd cache:magic:0:HTTP/1.0::AUTO:unchc %s:: ++ ++# /* XLD4(Q4) image format */ ++XLD(Q4):magic:11:MAJYO:.q4:PNM:q4toppm:: ++ ++# /* ML1 image format */ ++ML1:magic:0:\1\0\0\x1a:.ml1:PNM:ml1toppm %s:: ++ ++# /* Pict image format, 256 color only */ ++PICT:suffix:::.pict:PNM:picttoppm:PNM_RAW:ppmquant 256 | ppmtopict ++PICT(gzip):suffix:::.pict.gz:PNM:gzip -dc | picttoppm:PNM_RAW:ppmquant 256 | ppmtopict | gzip ++PICT(compress):suffix:::.pict.Z:PNM:compress -dc | picttoppm:PNM_RAW:ppmquant 256 | ppmtopict | compress ++ ++# /* Tim image format(used by SONY PlayStation) */ ++TIM:magic:0:\x10\x00\x00\x00:.tim:PNM:timtoppm:: ++ ++# /* Cam image format(used by CASIO QV-10) */ ++# /* CAM:magic:0:\x07\x20\x4d\x4d:.cam:AUTO:camtoppm -j:PNM_RAW */ ++CAM:magic:0:\x07\x20\x4d\x4d:.cam:PNM:camtoppm:: ++ ++# /* Portable Network Graphics (PNG) format : magic is "0x89 PNG" */ ++PNG:magic:0:\x89\x50\x4e\x47:.png:PNM:pngtopnm %s:PNM_RAW:pnmtopng ++# /* PNG(interlace):magic:0:\x89\x50\x4e\x47:.png:PNM:pngtopnm %s:PNM_RAW:pnmtopng -interlace */ ++ ++# /* DB-Z, SAURUS Freehand Memo, PV-F1 Action Board, Wiz Quick Memo format */ ++# /* Use xbm2free-1.10 or later. Old version is NOT a filter. */ ++# /* To show version of xbm2free, type "xbm2free" (with no argument). */ ++ZAURUS:magic:19:IMG1:.zau:PBM_ASCII:free2pbm:PBM:pbmtoxbm|xbm2free -s - ++DBZ:magic:19:IMG1:.dbz:::PBM:pbmtoxbm|xbm2free -d - ++PVF1:magic:12:IMG1:.pvf1:PBM_ASCII:free2pbm:PBM:pbmtoxbm|xbm2free -v - ++# /* WIZ:magic:19:IMG1:.wiz:::PBM:pbmtoxbm|xbm2free -w - */ ++ ++ ++ ++# /* Compress:magic:0:\037\235:.Z:AUTO:uncompress %s:: */ ++# /* Gzip:magic:0:\037\213:.gz:AUTO:gunzip %s:: */ ++# /* Gzip(old):magic:0:\037\236:.z:AUTO:gunzip %s:: */ ++ ++# /* MAKI:magic:0:MAKI01A\040:.mki:::: */ ++# /* MAKI:magic:0:MAKI01B\040:.mki:::: */ ++# /* MAG:magic:0:MAKI02\040\040:.mag:::: */ ++# /* Pi:magic:0:Pi:.pi:::: */ ++# /* PIC:magic:0:PIC:.pic:::: */ ++# /* PIC2:magic:0:P2DT:.p2:::: */ ++# /* PhotoCD:magic:0:\xff\xff\xff\xff:.pcd:::: */ ++ ++# /* PBM(ascii):magic:0:P1:.pbm:::: */ ++# /* PGM(ascii):magic:0:P2:.pgm:::: */ ++# /* PPM(ascii):magic:0:P3:.ppm:::: */ ++# /* PBM(raw):magic:0:P4:.pbm:::: */ ++# /* PGM(raw):magic:0:P5:.pgm:::: */ ++# /* PPM(raw):magic:0:P6:.ppm:::: */ ++ ++# /* Sun raster:magic:0:\131\246\152\225:.sun:::: */ ++# /* JFIF(JPEG):magic:0:\xff\xd8\xff:.jpg:::: */ ++# /* TIFF big-endian:magic:0:\115\115:.tif:::: */ ++# /* TIFF little-endian:magic:0:\111\111:.tif:::: */ ++# /* GIF(87):magic:0:GIF87a:.gif:::: */ ++# /* GIF(89):magic:0:GIF89a:.gif:::: */ ++# /* SGI(1):magic:0:\x01\xda:.rgb:::: */ ++# /* SGI(2):magic:0:\xda\x01:.rgb:::: */ ++# /* XWD:magic:0:\0\0\0\7: :::: */ +diff -ruN xv-3.10a-bugfixes/xvbmp.c xv-3.10a-enhancements/xvbmp.c +--- xv-3.10a-bugfixes/xvbmp.c 2005-03-27 18:12:17.000000000 -0800 ++++ xv-3.10a-enhancements/xvbmp.c 2005-04-17 13:56:31.000000000 -0700 +@@ -1,5 +1,5 @@ + /* +- * xvbmp.c - i/o routines for .BMP files (MS Windows 3.x) ++ * xvbmp.c - I/O routines for .BMP files (MS Windows 3.x and later; OS/2) + * + * LoadBMP(fname, numcols) + * WriteBMP(fp, pic, ptype, w, h, r, g, b, numcols, style); +@@ -9,30 +9,39 @@ + + #include "xv.h" + +-/* comments on error handling: +- a truncated file is not considered a Major Error. The file is loaded, the +- rest of the pic is filled with 0's. +- +- a file with garbage characters in it is an unloadable file. All allocated +- stuff is tossed, and LoadBMP returns non-zero +- +- not being able to malloc is a Fatal Error. The program is aborted. */ +- +- +-#define BI_RGB 0 +-#define BI_RLE8 1 +-#define BI_RLE4 2 ++/* Comments on error-handling: ++ A truncated file is not considered a Major Error. The file is loaded, ++ and the rest of the pic is filled with 0's. ++ ++ A file with garbage characters in it is an unloadable file. All allocated ++ stuff is tossed, and LoadBMP returns non-zero. ++ ++ Not being able to malloc is a Fatal Error. The program is aborted. */ ++ ++ ++#define BI_RGB 0 /* a.k.a. uncompressed */ ++#define BI_RLE8 1 ++#define BI_RLE4 2 ++#define BI_BITFIELDS 3 /* BMP version 4 */ ++#define BI_JPEG 4 /* BMP version 5 (not yet supported) */ ++#define BI_PNG 5 /* BMP version 5 (not yet supported) */ + + #define WIN_OS2_OLD 12 + #define WIN_NEW 40 + #define OS2_NEW 64 + ++#if (defined(UINT_MAX) && UINT_MAX != 0xffffffffU) ++# error XV's BMP code requires 32-bit unsigned integer type, but u_int isn't ++#endif ++ + static long filesize; + + static int loadBMP1 PARM((FILE *, byte *, u_int, u_int)); + static int loadBMP4 PARM((FILE *, byte *, u_int, u_int, u_int)); + static int loadBMP8 PARM((FILE *, byte *, u_int, u_int, u_int)); +-static int loadBMP24 PARM((FILE *, byte *, u_int, u_int)); ++static int loadBMP16 PARM((FILE *, byte *, u_int, u_int, u_int *)); ++static int loadBMP24 PARM((FILE *, byte *, u_int, u_int, u_int)); ++static int loadBMP32 PARM((FILE *, byte *, u_int, u_int, u_int *)); + static u_int getshort PARM((FILE *)); + static u_int getint PARM((FILE *)); + static void putshort PARM((FILE *, int)); +@@ -52,15 +61,14 @@ + PICINFO *pinfo; + /*******************************************/ + { +- FILE *fp; +- int i, c, c1, rv; +- u_int bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes; +- u_int biBitCount, biCompression, biSizeImage, biXPelsPerMeter; +- u_int biYPelsPerMeter, biClrUsed, biClrImportant; +- int bPad; +- char *cmpstr; +- byte *pic24, *pic8; +- char buf[512], *bname; ++ FILE *fp; ++ int i, c, c1, rv, bPad; ++ u_int bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes; ++ u_int biBitCount, biCompression, biSizeImage, biXPelsPerMeter; ++ u_int biYPelsPerMeter, biClrUsed, biClrImportant; ++ u_int colormask[3]; ++ char buf[512], *bname, *cmpstr, rgb_bits[16]; ++ byte *pic24, *pic8; + + /* returns '1' on success */ + +@@ -98,14 +106,13 @@ + biClrUsed = getint(fp); + biClrImportant = getint(fp); + } +- + else { /* old bitmap format */ + biWidth = getshort(fp); /* Types have changed ! */ + biHeight = getshort(fp); + biPlanes = getshort(fp); + biBitCount = getshort(fp); + +- /* Not in old versions so have to compute them*/ ++ /* not in old versions, so have to compute them */ + biSizeImage = (((biPlanes * biBitCount*biWidth)+31)/32)*4*biHeight; + + biCompression = BI_RGB; +@@ -126,25 +133,39 @@ + if (FERROR(fp)) { bmpError(bname,"EOF reached in file header"); goto ERROR; } + + +- /* error checking */ +- if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 && biBitCount!=24) || +- biPlanes!=1 || biCompression>BI_RLE4 || ++ /* error-checking */ ++ if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 && ++ biBitCount!=16 && biBitCount!=24 && biBitCount!=32) || ++ biPlanes!=1 || biCompression>BI_PNG || + biWidth<=0 || biHeight<=0 || + (biClrUsed && biClrUsed > (1 << biBitCount))) { + + sprintf(buf, +- "Bogus BMP File! (%dx%d, Bits=%d, Colors=%d, Planes=%d, Compr=%d)", ++ "Unsupported BMP type (%dx%d, Bits=%d, Colors=%d, Planes=%d, " ++ "Compr=%d)", + biWidth, biHeight, biBitCount, biClrUsed, biPlanes, biCompression); + + bmpError(bname, buf); + goto ERROR; + } + ++ if (biCompression>BI_BITFIELDS) { ++ sprintf(buf, "Unsupported BMP compression method (%s)", ++ biCompression == BI_JPEG? "JPEG" : ++ biCompression == BI_PNG? "PNG" : ++ "unknown/newer than v5"); ++ ++ bmpError(bname, buf); ++ goto ERROR; ++ } ++ + if (((biBitCount==1 || biBitCount==24) && biCompression != BI_RGB) || +- (biBitCount==4 && biCompression==BI_RLE8) || +- (biBitCount==8 && biCompression==BI_RLE4)) { ++ (biBitCount==4 && biCompression!=BI_RGB && biCompression!=BI_RLE4) || ++ (biBitCount==8 && biCompression!=BI_RGB && biCompression!=BI_RLE8) || ++ ((biBitCount==16 || biBitCount==32) && ++ biCompression!=BI_RGB && biCompression!=BI_BITFIELDS)) { + +- sprintf(buf,"Bogus BMP File! (bitCount=%d, Compression=%d)", ++ sprintf(buf,"Unsupported BMP type (bitCount=%d, Compression=%d)", + biBitCount, biCompression); + + bmpError(bname, buf); +@@ -156,20 +177,23 @@ + if (biSize != WIN_OS2_OLD) { + /* skip ahead to colormap, using biSize */ + c = biSize - 40; /* 40 bytes read from biSize to biClrImportant */ +- for (i=0; i<c; i++) getc(fp); +- ++ for (i=0; i<c; i++) ++ getc(fp); + bPad = bfOffBits - (biSize + 14); + } + ++ /* 16-bit or 32-bit color mask */ ++ if (biCompression==BI_BITFIELDS) { ++ colormask[0] = getint(fp); ++ colormask[1] = getint(fp); ++ colormask[2] = getint(fp); ++ bPad -= 12; ++ } ++ + /* load up colormap, if any */ +- if (biBitCount!=24) { ++ if (biBitCount == 1 || biBitCount == 4 || biBitCount == 8) { + int i, cmaplen; + +-/* this is superfluous; see identical test in "error checking" block above +- if (biClrUsed > (1 << biBitCount)) +- biClrUsed = (1 << biBitCount); +- */ +- + cmaplen = (biClrUsed) ? biClrUsed : 1 << biBitCount; + for (i=0; i<cmaplen; i++) { + pinfo->b[i] = getc(fp); +@@ -205,7 +229,7 @@ + + /* create pic8 or pic24 */ + +- if (biBitCount==24) { ++ if (biBitCount==16 || biBitCount==24 || biBitCount==32) { + u_int npixels = biWidth * biHeight; + u_int count = 3 * npixels; + +@@ -227,19 +251,35 @@ + WaitCursor(); + + /* load up the image */ +- if (biBitCount == 1) rv = loadBMP1(fp,pic8,biWidth,biHeight); +- else if (biBitCount == 4) rv = loadBMP4(fp,pic8,biWidth,biHeight, +- biCompression); +- else if (biBitCount == 8) rv = loadBMP8(fp,pic8,biWidth,biHeight, +- biCompression); +- else rv = loadBMP24(fp,pic24,biWidth,biHeight); ++ switch (biBitCount) { ++ case 1: ++ rv = loadBMP1(fp, pic8, biWidth, biHeight); ++ break; ++ case 4: ++ rv = loadBMP4(fp, pic8, biWidth, biHeight, biCompression); ++ break; ++ case 8: ++ rv = loadBMP8(fp, pic8, biWidth, biHeight, biCompression); ++ break; ++ case 16: ++ rv = loadBMP16(fp, pic24, biWidth, biHeight, /* v-- BI_RGB */ ++ biCompression == BI_BITFIELDS? colormask : NULL); ++ break; ++ default: ++ if (biBitCount == 32 && biCompression == BI_BITFIELDS) ++ rv = loadBMP32(fp, pic24, biWidth, biHeight, colormask); ++ else /* 24 or (32 and BI_RGB) */ ++ rv = loadBMP24(fp, pic24, biWidth, biHeight, biBitCount); ++ break; ++ } + + if (rv) bmpError(bname, "File appears truncated. Winging it."); + ++ + fclose(fp); + + +- if (biBitCount == 24) { ++ if (biBitCount > 8) { + pinfo->pic = pic24; + pinfo->type = PIC24; + } +@@ -251,6 +291,22 @@ + cmpstr = ""; + if (biCompression == BI_RLE4) cmpstr = ", RLE4 compressed"; + else if (biCompression == BI_RLE8) cmpstr = ", RLE8 compressed"; ++ else if (biCompression == BI_BITFIELDS) { ++ int bit, c[3], i; ++ u_int mask; ++ ++ for (i = 0; i < 3; ++i) { ++ mask = colormask[i]; ++ c[i] = 0; ++ for (bit = 0; bit < 32; ++bit) { ++ if (mask & 1) ++ ++c[i]; ++ mask >>= 1; ++ } ++ } ++ sprintf(rgb_bits, ", RGB%d%d%d", c[0], c[1], c[2]); ++ cmpstr = rgb_bits; ++ } + + pinfo->w = biWidth; pinfo->h = biHeight; + pinfo->normw = pinfo->w; pinfo->normh = pinfo->h; +@@ -282,12 +338,13 @@ + u_int w,h; + { + int i,j,c,bitnum,padw; +- byte *pp; ++ byte *pp = pic8 + ((h - 1) * w); ++ size_t l = w*h; + + c = 0; + padw = ((w + 31)/32) * 32; /* 'w', padded to be a multiple of 32 */ + +- for (i=h-1; i>=0; i--) { ++ for (i=h-1; i>=0 && (pp - pic8 <= l); i--) { + pp = pic8 + (i * w); + if ((i&0x3f)==0) WaitCursor(); + for (j=bitnum=0; j<padw; j++,bitnum++) { +@@ -316,8 +373,8 @@ + u_int w,h,comp; + { + int i,j,c,c1,x,y,nybnum,padw,rv; +- byte *pp; +- ++ byte *pp = pic8 + ((h - 1) * w); ++ size_t l = w*h; + + rv = 0; + c = c1 = 0; +@@ -325,7 +382,7 @@ + if (comp == BI_RGB) { /* read uncompressed data */ + padw = ((w + 7)/8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */ + +- for (i=h-1; i>=0; i--) { ++ for (i=h-1; i>=0 && (pp - pic8 <= l); i--) { + pp = pic8 + (i * w); + if ((i&0x3f)==0) WaitCursor(); + +@@ -353,7 +410,7 @@ + + if (c) { /* encoded mode */ + c1 = getc(fp); +- for (i=0; i<c; i++,x++,pp++) ++ for (i=0; i<c && (pp - pic8 <= l); i++,x++,pp++) + *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); + } + +@@ -373,7 +430,7 @@ + } + + else { /* absolute mode */ +- for (i=0; i<c; i++, x++, pp++) { ++ for (i=0; i<c && (pp - pic8 <= l); i++, x++, pp++) { + if ((i&1) == 0) c1 = getc(fp); + *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); + } +@@ -402,14 +459,18 @@ + u_int w,h,comp; + { + int i,j,c,c1,padw,x,y,rv; +- byte *pp; ++ byte *pp = pic8 + ((h - 1) * w); ++ size_t l = w*h; ++ byte *pend; + + rv = 0; + ++ pend = pic8 + w * h; ++ + if (comp == BI_RGB) { /* read uncompressed data */ + padw = ((w + 3)/4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */ + +- for (i=h-1; i>=0; i--) { ++ for (i=h-1; i>=0 && (pp - pic8 <= l); i--) { + pp = pic8 + (i * w); + if ((i&0x3f)==0) WaitCursor(); + +@@ -425,12 +486,12 @@ + x = y = 0; + pp = pic8 + x + (h-y-1)*w; + +- while (y<h) { ++ while (y<h && pp<=pend) { + c = getc(fp); if (c == EOF) { rv = 1; break; } + + if (c) { /* encoded mode */ + c1 = getc(fp); +- for (i=0; i<c; i++,x++,pp++) *pp = c1; ++ for (i=0; i<c && pp<=pend; i++,x++,pp++) *pp = c1; + } + + else { /* c==0x00 : escape codes */ +@@ -449,7 +510,7 @@ + } + + else { /* absolute mode */ +- for (i=0; i<c; i++, x++, pp++) { ++ for (i=0; i<c && pp<=pend; i++, x++, pp++) { + c1 = getc(fp); + *pp = c1; + } +@@ -472,26 +533,133 @@ + + + /*******************************************/ +-static int loadBMP24(fp, pic24, w, h) ++static int loadBMP16(fp, pic24, w, h, mask) ++ FILE *fp; ++ byte *pic24; ++ u_int w, h, *mask; ++{ ++ int x, y; ++ byte *pp = pic24 + ((h - 1) * w * 3); ++ size_t l = w*h*3; ++ u_int buf, colormask[6]; ++ int i, bit, bitshift[6], colorbits[6], bitshift2[6]; ++ ++ if (mask == NULL) { /* RGB555 */ ++ colormask[0] = 0x00007c00; ++ colormask[1] = 0x000003e0; ++ colormask[2] = 0x0000001f; ++ colormask[3] = 0x7c000000; ++ colormask[4] = 0x03e00000; ++ colormask[5] = 0x001f0000; ++ bitshift[0] = 7; bitshift2[0] = 0; ++ bitshift[1] = 2; bitshift2[1] = 0; ++ bitshift[2] = 0; bitshift2[2] = 3; ++ bitshift[3] = 23; bitshift2[3] = 0; ++ bitshift[4] = 18; bitshift2[4] = 0; ++ bitshift[5] = 13; bitshift2[5] = 0; ++ } else { ++ colormask[0] = mask[0]; ++ colormask[1] = mask[1]; ++ colormask[2] = mask[2]; ++ colormask[3] = (mask[0] & 0xffff) << 16; ++ colormask[4] = (mask[1] & 0xffff) << 16; ++ colormask[5] = (mask[2] & 0xffff) << 16; ++ ++ for (i = 0; i < 3; ++i) { ++ buf = colormask[i]; ++ ++ bitshift[i] = 0; ++ for (bit = 0; bit < 32; ++bit) { ++ if (buf & 1) ++ break; ++ else ++ ++bitshift[i]; ++ buf >>= 1; ++ } ++ bitshift[i+3] = bitshift[i] + 16; ++ ++ colorbits[i] = 0; ++ for (; bit < 32; ++bit) { ++ if (buf & 1) ++ ++colorbits[i]; ++ else ++ break; ++ buf >>= 1; ++ } ++ if (colorbits[i] > 8) { /* over 8-bit depth */ ++ bitshift[i] += (colorbits[i] - 8); ++ bitshift[i+3] = bitshift[i] + 16; ++ bitshift2[i] = bitshift2[i+3] = 0; ++ } else ++ bitshift2[i] = bitshift2[i+3] = 8 - colorbits[i]; ++ } ++ } ++ ++ if (DEBUG > 1) ++ fprintf(stderr, "loadBMP16: bitfields\n" ++ "\tR: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n" ++ "\t (mask = %08x, shift >>%2d, <<%2d)\n" ++ "\tG: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n" ++ "\t (mask = %08x, shift >>%2d, <<%2d)\n" ++ "\tB: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n" ++ "\t (mask = %08x, shift >>%2d, <<%2d)\n", ++ colorbits[0], colormask[0], bitshift[0], bitshift2[0], ++ colormask[3], bitshift[3], bitshift2[3], ++ colorbits[1], colormask[1], bitshift[1], bitshift2[1], ++ colormask[4], bitshift[4], bitshift2[4], ++ colorbits[2], colormask[2], bitshift[2], bitshift2[2], ++ colormask[5], bitshift[5], bitshift2[5]); ++ ++ for (y = h-1; y >= 0 && (pp - pic24 <= l); y--) { ++ pp = pic24 + (3 * w * y); ++ if ((y&0x3f)==0) WaitCursor(); ++ ++ for (x = w; x > 1; x -= 2) { ++ buf = getint(fp); ++ *(pp++) = (buf & colormask[0]) >> bitshift[0] << bitshift2[0]; ++ *(pp++) = (buf & colormask[1]) >> bitshift[1] << bitshift2[1]; ++ *(pp++) = (buf & colormask[2]) >> bitshift[2] << bitshift2[2]; ++ *(pp++) = (buf & colormask[3]) >> bitshift[3] << bitshift2[3]; ++ *(pp++) = (buf & colormask[4]) >> bitshift[4] << bitshift2[4]; ++ *(pp++) = (buf & colormask[5]) >> bitshift[5] << bitshift2[5]; ++ } ++ if (w & 1) { /* padded to 2 pix */ ++ buf = getint(fp); ++ *(pp++) = (buf & colormask[0]) >> bitshift[0]; ++ *(pp++) = (buf & colormask[1]) >> bitshift[1]; ++ *(pp++) = (buf & colormask[2]) >> bitshift[2]; ++ } ++ } ++ ++ return FERROR(fp)? 1 : 0; ++} ++ ++ ++ ++/*******************************************/ ++static int loadBMP24(fp, pic24, w, h, bits) /* also handles 32-bit BI_RGB */ + FILE *fp; + byte *pic24; +- u_int w,h; ++ u_int w,h, bits; + { + int i,j,padb,rv; +- byte *pp; ++ byte *pp = pic24 + ((h - 1) * w * 3); ++ size_t l = w*h*3; + + rv = 0; + + padb = (4 - ((w*3) % 4)) & 0x03; /* # of pad bytes to read at EOscanline */ ++ if (bits==32) padb = 0; + + for (i=h-1; i>=0; i--) { + pp = pic24 + (i * w * 3); + if ((i&0x3f)==0) WaitCursor(); + +- for (j=0; j<w; j++) { ++ for (j=0; j<w && (pp - pic24 <= l); j++) { + pp[2] = getc(fp); /* blue */ + pp[1] = getc(fp); /* green */ + pp[0] = getc(fp); /* red */ ++ if (bits==32) getc(fp); + pp += 3; + } + +@@ -507,6 +675,70 @@ + + + /*******************************************/ ++static int loadBMP32(fp, pic24, w, h, colormask) /* 32-bit BI_BITFIELDS only */ ++ FILE *fp; ++ byte *pic24; ++ u_int w, h, *colormask; ++{ ++ int x, y; ++ byte *pp; ++ u_int buf; ++ int i, bit, bitshift[3], colorbits[3], bitshift2[3]; ++ ++ for (i = 0; i < 3; ++i) { ++ buf = colormask[i]; ++ ++ bitshift[i] = 0; ++ for (bit = 0; bit < 32; ++bit) { ++ if (buf & 1) ++ break; ++ else ++ ++bitshift[i]; ++ buf >>= 1; ++ } ++ ++ colorbits[i] = 0; ++ for (; bit < 32; ++bit) { ++ if (buf & 1) ++ ++colorbits[i]; ++ else ++ break; ++ buf >>= 1; ++ } ++ if (colorbits[i] > 8) { /* over 8-bit depth */ ++ bitshift[i] += (colorbits[i] - 8); ++ bitshift2[i] = 0; ++ } else ++ bitshift2[i] = 8 - colorbits[i]; ++ } ++ ++ if (DEBUG > 1) ++ fprintf(stderr, "loadBMP32: bitfields\n" ++ "\tR: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n" ++ "\tG: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n" ++ "\tB: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n", ++ colorbits[0], colormask[0], bitshift[0], bitshift2[0], ++ colorbits[1], colormask[1], bitshift[1], bitshift2[1], ++ colorbits[2], colormask[2], bitshift[2], bitshift2[2]); ++ ++ for (y = h-1; y >= 0; y--) { ++ pp = pic24 + (3 * w * y); ++ if ((y&0x3f)==0) WaitCursor(); ++ ++ for(x = w; x > 0; x --) { ++ buf = getint(fp); ++ *(pp++) = (buf & colormask[0]) >> bitshift[0] << bitshift2[0]; ++ *(pp++) = (buf & colormask[1]) >> bitshift[1] << bitshift2[1]; ++ *(pp++) = (buf & colormask[2]) >> bitshift[2] << bitshift2[2]; ++ } ++ } ++ ++ return FERROR(fp)? 1 : 0; ++} ++ ++ ++ ++/*******************************************/ + static u_int getshort(fp) + FILE *fp; + { +@@ -523,7 +755,7 @@ + int c, c1, c2, c3; + c = getc(fp); c1 = getc(fp); c2 = getc(fp); c3 = getc(fp); + return ((u_int) c) + +- (((u_int) c1) << 8) + ++ (((u_int) c1) << 8) + + (((u_int) c2) << 16) + + (((u_int) c3) << 24); + } +diff -ruN xv-3.10a-bugfixes/xvbrowse.c xv-3.10a-enhancements/xvbrowse.c +--- xv-3.10a-bugfixes/xvbrowse.c 2004-05-16 18:01:25.000000000 -0700 ++++ xv-3.10a-enhancements/xvbrowse.c 2005-04-25 23:30:27.000000000 -0700 +@@ -24,6 +24,10 @@ + typedef unsigned int mode_t; /* file mode bits */ + #endif + ++#ifndef MAX ++# define MAX(a,b) (((a)>(b))?(a):(b)) /* used only for wheelmouse support */ ++#endif ++ + + /* load up built-in icons */ + #include "bits/br_file" +@@ -36,6 +40,7 @@ + #include "bits/br_error" + /* #include "bits/br_unknown" commented out (near line 492) */ + #include "bits/br_cmpres" ++#include "bits/br_bzip2" + + #include "bits/br_gif" + #include "bits/br_pm" +@@ -50,11 +55,20 @@ + #include "bits/br_tiff" + #include "bits/br_pds" + #include "bits/br_ps" ++#include "bits/br_pcd" + #include "bits/br_iff" + #include "bits/br_targa" + #include "bits/br_xpm" + #include "bits/br_xwd" + #include "bits/br_fits" ++#include "bits/br_png" ++#include "bits/br_zx" /* [JCE] The Spectrum+3 icon */ ++#include "bits/br_mag" ++#include "bits/br_maki" ++#include "bits/br_pic" ++#include "bits/br_pi" ++#include "bits/br_pic2" ++#include "bits/br_mgcsfx" + + #include "bits/br_trash" + #include "bits/fcurs" +@@ -94,14 +108,23 @@ + #define BF_XPM 25 + #define BF_XWD 26 + #define BF_FITS 27 +-#define BF_MAX 28 /* # of built-in icons */ ++#define BF_PNG 28 ++#define BF_ZX 29 /* [JCE] Spectrum SCREEN$ */ ++#define BF_PCD 30 ++#define BF_BZIP2 31 ++#define JP_EXT_BF (BF_BZIP2) ++#define BF_MAG (JP_EXT_BF + 1) ++#define BF_MAKI (JP_EXT_BF + 2) ++#define BF_PIC (JP_EXT_BF + 3) ++#define BF_PI (JP_EXT_BF + 4) ++#define BF_PIC2 (JP_EXT_BF + 5) ++#define BF_MGCSFX (JP_EXT_BF + 6) ++#define JP_EXT_BF_END (BF_MGCSFX) ++#define BF_MAX (JP_EXT_BF_END + 1) /* # of built-in icons */ + + #define ISLOADABLE(ftyp) (ftyp!=BF_DIR && ftyp!=BF_CHR && ftyp!=BF_BLK && \ + ftyp!=BF_SOCK && ftyp!=BF_FIFO) + +-#define DEF_BROWWIDE 615 /* default size of window */ +-#define DEF_BROWHIGH 356 +- + #define SCROLLVERT 8 /* height of scroll region at top/bottom of iconw */ + #define PAGEVERT 40 /* during rect drag, if further than this, page */ + +@@ -113,16 +136,35 @@ + #define BOTMARGIN 58 /* room for a row of buttons and a line of text */ + #define LRMARGINS 5 /* left and right margins */ + +-#define ISIZE_WIDE 80 /* maximum size of an icon */ +-#define ISIZE_HIGH 60 ++/* some people like bigger icons; 4:3 aspect ratio is recommended ++ * (NOTE: standard XV binaries will not be able to read larger icons!) */ ++#ifndef ISIZE_WIDE ++# define ISIZE_WIDE 80 /* maximum size of an icon */ ++#endif ++#ifndef ISIZE_HIGH ++# define ISIZE_HIGH 60 ++#endif + +-#define ISPACE_WIDE (ISIZE_WIDE+16) /* icon spacing */ ++#ifndef ISIZE_WPAD ++# define ISIZE_WPAD 16 /* extra horizontal padding between icons */ ++#endif ++ ++#ifndef INUM_WIDE ++# define INUM_WIDE 6 /* size initial window to hold this many icons */ ++#endif ++#ifndef INUM_HIGH ++# define INUM_HIGH 3 ++#endif ++ ++#define ISPACE_WIDE (ISIZE_WIDE+ISIZE_WPAD) /* icon spacing */ + #define ISPACE_TOP 4 /* dist btwn top of ISPACE and ISIZE */ + #define ISPACE_TTOP 4 /* dist btwn bot of icon and title */ + #define ISPACE_HIGH (ISIZE_HIGH+ISPACE_TOP+ISPACE_TTOP+16+4) + + #define DBLCLICKTIME 300 /* milliseconds */ + ++#define COUNT(x) (sizeof (x) / sizeof (x)[0]) ++ + /* button/menu indicies */ + #define BR_CHDIR 0 + #define BR_DELETE 1 +@@ -140,12 +182,23 @@ + #define BR_NBUTTS 13 /* # of command buttons */ + #define BR_SEP1 13 /* separator */ + #define BR_HIDDEN 14 ++#ifdef AUTO_EXPAND ++#define BR_CLEARVD 15 ++#define BR_SELFILES 16 ++#define BR_NCMDS 17 /* # of menu commands */ ++#else + #define BR_SELFILES 15 + #define BR_NCMDS 16 /* # of menu commands */ ++#endif + + #define BUTTW 80 + #define BUTTH 24 + ++/* original size of window was 615 x 356 (for 80x60 thumbnails in 6x3 array) */ ++#define DEF_BROWWIDE (ISPACE_WIDE * INUM_WIDE + LRMARGINS * 2 + 29) ++#define DEF_BROWHIGH (ISPACE_HIGH * INUM_HIGH + BUTTH * 2 + 16 + 28) ++/* last number is a fudge--e.g., extra spaces, borders, etc. -----^ */ ++ + static char *showHstr = "Show hidden files"; + static char *hideHstr = "Hide 'hidden' files"; + +@@ -164,6 +217,9 @@ + "Close window\t^c", + MBSEP, + "Show hidden files", /* no equiv */ ++#ifdef AUTO_EXPAND ++ "Clear virtual directory", ++#endif + "Select files...\t^f" + }; + +@@ -209,6 +265,13 @@ + } BROWINFO; + + ++/* keep track of last icon visible in each path */ ++typedef struct IVIS IVIS; ++ struct IVIS { IVIS *next; ++ char *name; ++ int icon; ++ }; ++ + static Cursor movecurs, copycurs, delcurs; + static BROWINFO binfo[MAXBRWIN]; + static Pixmap bfIcons[BF_MAX], trashPix; +@@ -294,10 +357,16 @@ + static void cp_special PARM((struct stat *, int)); + static void cp_fifo PARM((struct stat *, int)); + ++#ifdef AUTO_EXPAND ++static int stat2bf PARM((u_int, char *)); ++#else + static int stat2bf PARM((u_int)); ++#endif + + static int selmatch PARM((char *, char *)); + static int selmatch1 PARM((char *, char *)); ++static void recIconVisible PARM((char *, int)); ++static void restIconVisible PARM((BROWINFO *)); + + + +@@ -511,9 +580,10 @@ + bfIcons[BF_JFIF]=MakePix1(br->win,br_jfif_bits,br_jfif_width,br_jfif_height); + bfIcons[BF_TIFF]=MakePix1(br->win,br_tiff_bits,br_tiff_width,br_tiff_height); + bfIcons[BF_PDS] =MakePix1(br->win,br_pds_bits, br_pds_width, br_pds_height); +- +- bfIcons[BF_COMPRESS]= MakePix1(br->win, br_cmpres_bits, +- br_cmpres_width, br_cmpres_height); ++ bfIcons[BF_COMPRESS] = MakePix1(br->win, br_cmpres_bits, ++ br_cmpres_width, br_cmpres_height); ++ bfIcons[BF_BZIP2] = MakePix1(br->win, br_bzip2_bits, ++ br_bzip2_width, br_bzip2_height); + + bfIcons[BF_PS] =MakePix1(br->win,br_ps_bits, br_ps_width, br_ps_height); + bfIcons[BF_IFF] =MakePix1(br->win,br_iff_bits, br_iff_width, br_iff_height); +@@ -524,6 +594,16 @@ + bfIcons[BF_XPM] =MakePix1(br->win,br_xpm_bits, br_xpm_width, br_xpm_height); + bfIcons[BF_XWD] =MakePix1(br->win,br_xwd_bits, br_xwd_width, br_xwd_height); + bfIcons[BF_FITS]=MakePix1(br->win,br_fits_bits,br_fits_width,br_fits_height); ++ bfIcons[BF_PNG] =MakePix1(br->win,br_png_bits, br_png_width, br_png_height); ++ bfIcons[BF_ZX] =MakePix1(br->win,br_zx_bits, br_zx_width, br_zx_height); ++ bfIcons[BF_PCD] =MakePix1(br->win,br_pcd_bits, br_pcd_width, br_pcd_height); ++ bfIcons[BF_MAG] =MakePix1(br->win,br_mag_bits, br_mag_width, br_mag_height); ++ bfIcons[BF_MAKI]=MakePix1(br->win,br_maki_bits,br_maki_width,br_maki_height); ++ bfIcons[BF_PIC] =MakePix1(br->win,br_pic_bits, br_pic_width, br_pic_height); ++ bfIcons[BF_PI] =MakePix1(br->win,br_pi_bits, br_pi_width, br_pi_height); ++ bfIcons[BF_PIC2]=MakePix1(br->win,br_pic2_bits,br_pic2_width,br_pic2_height); ++ bfIcons[BF_MGCSFX] = MakePix1(br->win,br_mgcsfx_bits, ++ br_mgcsfx_width,br_mgcsfx_height); + + + /* check that they all got built */ +@@ -698,6 +778,9 @@ + } + } + ++#ifdef VS_RESCMAP ++static int _IfTempOut=0; ++#endif + + /***************************************************************/ + void KillBrowseWindows() +@@ -730,7 +813,6 @@ + return 0; + } + +- + /***************************************************************/ + static int brChkEvent(br, xev) + BROWINFO *br; +@@ -745,15 +827,32 @@ + + if (!hasBeenSized) return 0; /* ignore evrythng until we get 1st Resize */ + ++ ++#ifdef VS_RESCMAP ++ /* force change color map if have LocalCmap */ ++ if (browPerfect && browCmap && (_IfTempOut==2)) { ++ int i; ++ XSetWindowAttributes xswa; ++ ++ xswa.colormap = LocalCmap? LocalCmap : theCmap; ++ for (i=0; i<MAXBRWIN; ++i) ++ XChangeWindowAttributes(theDisp, binfo[i].win, CWColormap, &xswa); ++ XFlush(theDisp); ++ _IfTempOut=1; ++ } ++#endif ++ + if (xev->type == Expose) { + int x,y,w,h; + XExposeEvent *e = (XExposeEvent *) xev; + x = e->x; y = e->y; w = e->width; h = e->height; + + /* throw away excess redraws for 'dumb' windows */ +- if (e->count > 0 && (e->window == br->scrl.win)) {} ++ if (e->count > 0 && (e->window == br->scrl.win)) ++ ; + +- else if (e->window == br->scrl.win) SCRedraw(&(br->scrl)); ++ else if (e->window == br->scrl.win) ++ SCRedraw(&(br->scrl)); + + else if (e->window == br->win || e->window == br->iconW) { /* smart wins */ + /* group individual expose rects into a single expose region */ +@@ -806,13 +905,57 @@ + int i,x,y; + x = e->x; y = e->y; + +- if (e->button == Button1) { ++#ifdef VS_RESCMAP ++ if (browCmap && browPerfect && (_IfTempOut!=0)) ++ { ++ XSetWindowAttributes xswa; ++ _IfTempOut--; ++ xswa.colormap = browCmap; ++ for(i=0;i<MAXBRWIN;i++) ++ XChangeWindowAttributes(theDisp, binfo[i].win, CWColormap, &xswa); ++ XFlush(theDisp); ++ } ++ ++#endif ++ ++ if (e->button == Button1) { + if (e->window == br->win) clickBrow(br,x,y); + else if (e->window == br->scrl.win) SCTrack(&(br->scrl),x,y); + else if (e->window == br->iconW) { + i = clickIconWin(br, x,y,(unsigned long) e->time, + (e->state&ControlMask) || (e->state&ShiftMask)); +- ++ } ++ else rv = 0; ++ } ++ else if (e->button == Button4) { /* note min vs. max, + vs. - */ ++ /* scroll regardless of where we are in the browser window */ ++ if (e->window == br->win || ++ e->window == br->scrl.win || ++ e->window == br->iconW) ++ { ++ SCRL *sp=&(br->scrl); ++ int halfpage=MAX(1,sp->page/2); /* user resize to 1 line? */ ++ ++ if (sp->val > sp->min+halfpage) ++ SCSetVal(sp,sp->val-halfpage); ++ else ++ SCSetVal(sp,sp->min); ++ } ++ else rv = 0; ++ } ++ else if (e->button == Button5) { /* note max vs. min, - vs. + */ ++ /* scroll regardless of where we are in the browser window */ ++ if (e->window == br->win || ++ e->window == br->scrl.win || ++ e->window == br->iconW) ++ { ++ SCRL *sp=&(br->scrl); ++ int halfpage=MAX(1,sp->page/2); /* user resize to 1 line? */ ++ ++ if (sp->val < sp->max-halfpage) ++ SCSetVal(sp,sp->val+halfpage); ++ else ++ SCSetVal(sp,sp->max); + } + else rv = 0; + } +@@ -1101,6 +1244,10 @@ + case BR_SELFILES: doSelFilesCmd(br); break; + + case BR_RECURSUP: doRecurseCmd(br); break; ++ ++#ifdef AUTO_EXPAND ++ case BR_CLEARVD: Vdsettle(); break; ++#endif + } + } + +@@ -1250,6 +1397,18 @@ + int i, allowtext; + + if (!nostr) setSelInfoStr(br, sel); ++#ifdef AUTO_EXPAND ++ if (Isvdir(br->path)) { ++ BTSetActive(&br->but[BR_DELETE], 0); ++ br->cmdMB.dim[BR_DELETE] = 1; ++ ++ BTSetActive(&br->but[BR_RENAME], 0); ++ br->cmdMB.dim[BR_RENAME] = 1; ++ ++ BTSetActive(&br->but[BR_MKDIR], 0); ++ br->cmdMB.dim[BR_MKDIR] = 1; ++ } else { ++#endif + BTSetActive(&br->but[BR_DELETE], br->numlit>0); + br->cmdMB.dim[BR_DELETE] = !(br->numlit>0); + +@@ -1258,6 +1417,11 @@ + + BTSetActive(&br->but[BR_GENICON], br->numlit>0); + br->cmdMB.dim[BR_GENICON] = !(br->numlit>0); ++#ifdef AUTO_EXPAND ++ BTSetActive(&br->but[BR_MKDIR], 1); ++ br->cmdMB.dim[BR_MKDIR] = 0; ++ } ++#endif + + /* turn on 'text view' cmd if exactly one non-dir is lit */ + allowtext = 0; +@@ -1318,8 +1482,11 @@ + struct stat st; + + sprintf(buf, "%s%s", br->path, bf->name); /* build filename */ ++#ifdef AUTO_EXPAND ++ Dirtovd(buf); ++#endif + if (stat(buf, &st) == 0) { +- sprintf(buf, "%s: %ld bytes", bf->name, st.st_size); ++ sprintf(buf, "%s: %ld bytes", bf->name, (long)st.st_size); + strcat(buf, buf1); + } + } +@@ -1598,6 +1765,10 @@ + { + int sval, first, numvis; + ++ /* if we know what path we have, remember last visible icon for this path */ ++ if (br->path) ++ recIconVisible(br->path, num); ++ + /* if icon #i isn't visible, adjust scrollbar so it *is* */ + + sval = br->scrl.val; +@@ -1649,29 +1820,14 @@ + return; + } + +- + /***************************************************************/ +-static int clickIconWin(br, mx, my, mtime, multi) +- BROWINFO *br; +- int mx,my,multi; +- unsigned long mtime; ++static int updateSel(br, sel, multi, mtime) ++ BROWINFO *br; ++ int sel, multi; ++ unsigned long mtime; + { +- /* returns '-1' normally, returns an index into bfList[] if the user +- double-clicks an icon */ +- +- int i,j, rv, sel, cpymode, dodel; +- BROWINFO *destBr; +- BFIL *bf; +- char buf[256], *destFolderName; +- +- rv = -1; /* default return value */ +- if (!br->bfList || !br->bfLen) return rv; +- +- destBr = br; destFolderName = "."; +- +- sel = mouseInWhichIcon(br, mx, my); +- +- dodel = 0; ++ int i; ++ BFIL *bf; + + if (sel == -1) { /* clicked on nothing */ + if (!multi) { /* deselect all */ +@@ -1728,11 +1884,12 @@ + + + /* see if we've double-clicked something */ +- if (sel==br->lastIconClicked && mtime-br->lastClickTime < DBLCLICKTIME) { ++ if (mtime && ++ sel==br->lastIconClicked && mtime-br->lastClickTime < DBLCLICKTIME) { + br->lastIconClicked = -1; /* YES */ + + doubleClick(br, sel); +- return rv; ++ return -1; + } + + else { +@@ -1741,9 +1898,36 @@ + } + } + +- + changedNumLit(br, -1, 0); ++ return 0; ++} ++ + ++/***************************************************************/ ++static int clickIconWin(br, mx, my, mtime, multi) ++ BROWINFO *br; ++ int mx,my,multi; ++ unsigned long mtime; ++{ ++ /* returns '-1' normally, returns an index into bfList[] if the user ++ double-clicks an icon */ ++ ++ int i,j, sel, cpymode, dodel; ++ BROWINFO *destBr; ++ BFIL *bf; ++ char buf[256], *destFolderName; ++ ++ if (!br->bfList || !br->bfLen) return -1; ++ ++ destBr = br; destFolderName = "."; ++ ++ sel = mouseInWhichIcon(br, mx, my); ++ dodel = 0; ++ ++ recIconVisible(br->path, sel); ++ ++ if (updateSel(br, sel, multi, mtime)) ++ return -1; + + + { /* track mouse until button1 is released */ +@@ -2098,7 +2282,7 @@ + } + } /* end of 'tracking' sub-function */ + +- return rv; ++ return -1; + } + + /*******************************************/ +@@ -2164,15 +2348,35 @@ + else sprintf(buf, "%s%s", br->path, br->bfList[sel].name); + #endif + ++#ifdef AUTO_EXPAND ++ if (Chvdir(buf)) { ++#else + if (chdir(buf)) { ++#endif + char str[512]; + sprintf(str,"Unable to cd to '%s'\n", br->bfList[sel].name); + setBrowStr(br, str); + XBell(theDisp, 50); + } + else { ++#ifdef AUTO_EXPAND ++ if (Isvdir(buf)) { ++ BTSetActive(&br->but[BR_DELETE], 0); ++ br->cmdMB.dim[BR_DELETE] = 1; ++ ++ BTSetActive(&br->but[BR_RENAME], 0); ++ br->cmdMB.dim[BR_RENAME] = 1; ++ ++ BTSetActive(&br->but[BR_MKDIR], 0); ++ br->cmdMB.dim[BR_MKDIR] = 1; ++ } else { ++ BTSetActive(&br->but[BR_MKDIR], 1); ++ br->cmdMB.dim[BR_MKDIR] = 0; ++ } ++#endif + scanDir(br); + SCSetVal(&(br->scrl), 0); /* reset to top on a chdir */ ++ restIconVisible(br); + } + } + +@@ -2193,6 +2397,28 @@ + } + else { *event_retP = LOADPIC; SetDirFName(buf); } + ++#ifdef VS_RESCMAP ++ /* Change Colormap for browser */ ++ if (browPerfect && browCmap) ++ { ++ int i; ++ XSetWindowAttributes xswa; ++ if(LocalCmap) ++ { ++ xswa.colormap = LocalCmap; ++ _IfTempOut=2; ++ } ++ else ++ { ++ xswa.colormap = theCmap; ++ _IfTempOut=2; ++ } ++ for(i=0;i<MAXBRWIN;i++) ++ XChangeWindowAttributes(theDisp, binfo[i].win, CWColormap, &xswa); ++ XFlush(theDisp); ++ } ++#endif ++ + *event_doneP = 1; /* make MainLoop load image */ + } + } +@@ -2347,6 +2573,9 @@ + + /* try to open this file */ + sprintf(foo, "%s%s", br->path, br->bfList[i].name); ++#ifdef AUTO_EXPAND ++ Dirtovd(foo); ++#endif + for (j=0; j<numnames && strcmp(namelist[j],foo); j++); + if (j<numnames) { + curname = nList.selected = j; +@@ -2362,6 +2591,9 @@ + else { /* not SPACE, or SPACE and lit=1 and not shift */ + for (i=0; i<br->bfLen && !br->bfList[i].lit; i++); /* find lit one */ + sprintf(fname, "%s%s", br->path, br->bfList[i].name); ++#ifdef AUTO_EXPAND ++ Dirtovd(fname); ++#endif + viewsel = !(strcmp(fname, fullfname)); + + if (viewsel) { +@@ -2553,7 +2785,11 @@ + } + #endif + ++#ifdef AUTO_EXPAND ++ if (Chvdir(tmppath)) { ++#else + if (chdir(tmppath)) { ++#endif + char str[512]; + sprintf(str,"Unable to cd to '%s'\n", tmppath); + MBRedraw(&(br->dirMB)); +@@ -2561,8 +2797,24 @@ + XBell(theDisp, 50); + } + else { ++#ifdef AUTO_EXPAND ++ if (Isvdir(tmppath)) { ++ BTSetActive(&br->but[BR_DELETE], 0); ++ br->cmdMB.dim[BR_DELETE] = 1; ++ ++ BTSetActive(&br->but[BR_RENAME], 0); ++ br->cmdMB.dim[BR_RENAME] = 1; ++ ++ BTSetActive(&br->but[BR_MKDIR], 0); ++ br->cmdMB.dim[BR_MKDIR] = 1; ++ } else { ++ BTSetActive(&br->but[BR_MKDIR], 1); ++ br->cmdMB.dim[BR_MKDIR] = 0; ++ } ++#endif + scanDir(br); + SCSetVal(&br->scrl, 0); /* reset to top of window on a chdir */ ++ restIconVisible(br); + } + } + } +@@ -2581,7 +2833,11 @@ + if ((strlen(br->path) > (size_t) 2) && br->path[strlen(br->path)-1] == '/') + br->path[strlen(br->path)-1] = '\0'; + ++#ifdef AUTO_EXPAND ++ rv = Chvdir(br->path); ++#else + rv = chdir(br->path); ++#endif + if (rv) { + char str[512]; + sprintf(str, "Unable to cd to '%s'\n", br->path); +@@ -2589,6 +2845,23 @@ + XBell(theDisp, 50); + } + ++#ifdef AUTO_EXPAND ++ if (Isvdir(br->path)) { ++ BTSetActive(&br->but[BR_DELETE], 0); ++ br->cmdMB.dim[BR_DELETE] = 1; ++ ++ BTSetActive(&br->but[BR_RENAME], 0); ++ br->cmdMB.dim[BR_RENAME] = 1; ++ ++ BTSetActive(&br->but[BR_MKDIR], 0); ++ br->cmdMB.dim[BR_MKDIR] = 1; ++ } else { ++ BTSetActive(&br->but[BR_MKDIR], 1); ++ br->cmdMB.dim[BR_MKDIR] = 0; ++ } ++#endif ++ ++ restIconVisible(br); + strcat(br->path, "/"); /* put trailing '/' back on */ + return rv; + } +@@ -2615,8 +2888,13 @@ + strcpy(dstbr->mblist[i], srcbr->mblist[i]); + } + +- dstbr->dirMB.list = srcbr->mblist; ++#if 0 ++ dstbr->dirMB.list = srcbr->mblist; /* original bug..? */ + dstbr->dirMB.nlist = srcbr->ndirs; ++#else ++ dstbr->dirMB.list = dstbr->mblist; /* fixed by */ ++ dstbr->dirMB.nlist = dstbr->ndirs; /* jp-extension. */ ++#endif + + XClearArea(theDisp, dstbr->dirMB.win, dstbr->dirMB.x, dstbr->dirMB.y, + dstbr->dirMB.w+3, dstbr->dirMB.h+3, False); +@@ -2974,7 +3252,11 @@ + + + if (stat(bf->name, &st)==0) { ++#ifdef AUTO_EXPAND ++ bf->ftype = stat2bf((u_int) st.st_mode , bf->name); ++#else + bf->ftype = stat2bf((u_int) st.st_mode); ++#endif + if (bf->ftype == BF_FILE && (st.st_mode & 0111)) bf->ftype = BF_EXE; + + switch (bf->ftype) { +@@ -3006,6 +3288,7 @@ + case RFT_XBM: bf->ftype = BF_XBM; break; + case RFT_SUNRAS: bf->ftype = BF_SUNRAS; break; + case RFT_BMP: bf->ftype = BF_BMP; break; ++ case RFT_WBMP: bf->ftype = BF_BMP; break; + case RFT_UTAHRLE: bf->ftype = BF_UTAHRLE; break; + case RFT_IRIS: bf->ftype = BF_IRIS; break; + case RFT_PCX: bf->ftype = BF_PCX; break; +@@ -3013,12 +3296,22 @@ + case RFT_TIFF: bf->ftype = BF_TIFF; break; + case RFT_PDSVICAR: bf->ftype = BF_PDS; break; + case RFT_COMPRESS: bf->ftype = BF_COMPRESS; break; ++ case RFT_BZIP2: bf->ftype = BF_BZIP2; break; + case RFT_PS: bf->ftype = BF_PS; break; + case RFT_IFF: bf->ftype = BF_IFF; break; + case RFT_TARGA: bf->ftype = BF_TARGA; break; + case RFT_XPM: bf->ftype = BF_XPM; break; + case RFT_XWD: bf->ftype = BF_XWD; break; + case RFT_FITS: bf->ftype = BF_FITS; break; ++ case RFT_PNG: bf->ftype = BF_PNG; break; ++ case RFT_ZX: bf->ftype = BF_ZX; break; /* [JCE] */ ++ case RFT_PCD: bf->ftype = BF_PCD; break; ++ case RFT_MAG: bf->ftype = BF_MAG; break; ++ case RFT_MAKI: bf->ftype = BF_MAKI; break; ++ case RFT_PIC: bf->ftype = BF_PIC; break; ++ case RFT_PI: bf->ftype = BF_PI; break; ++ case RFT_PIC2: bf->ftype = BF_PIC2; break; ++ case RFT_MGCSFX: bf->ftype = BF_MGCSFX; break; + } + } + } +@@ -3405,7 +3698,7 @@ + double wexpand,hexpand; + int iwide, ihigh; + byte *icon24, *icon8; +- char str[256], str1[256], *readname, uncompname[128]; ++ char str[256], str1[256], readname[128], uncompname[128]; + char basefname[128], *uncName; + + +@@ -3414,7 +3707,7 @@ + basefname[0] = '\0'; + pinfo.pic = (byte *) NULL; + pinfo.comment = (char *) NULL; +- readname = bf->name; ++ strncpy(readname, bf->name, sizeof(readname) - 1); + + /* free any old info in 'bf' */ + if (bf->imginfo) free (bf->imginfo); +@@ -3431,7 +3724,7 @@ + + filetype = ReadFileType(bf->name); + +- if (filetype == RFT_COMPRESS) { ++ if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) { + #if (defined(VMS) && !defined(GUNZIP)) + /* VMS decompress doesn't like the file to have a trailing .Z in fname + however, GUnZip is OK with it, which we are calling UnCompress */ +@@ -3442,9 +3735,9 @@ + uncName = bf->name; + #endif + +- if (UncompressFile(uncName, uncompname)) { ++ if (UncompressFile(uncName, uncompname, filetype)) { + filetype = ReadFileType(uncompname); +- readname = uncompname; ++ strncpy(readname, uncompname, sizeof(readname) - 1); + } + else { + sprintf(str, "Couldn't uncompress file '%s'", bf->name); +@@ -3453,6 +3746,56 @@ + } + } + ++#ifdef MACBINARY ++ if (handlemacb && macb_file == True && bf->ftype != BF_ERROR) { ++ if (RemoveMacbinary(readname, uncompname)) { ++ if (strcmp(readname, bf->name)!=0) unlink(readname); ++ strncpy(readname, uncompname, sizeof(readname) - 1); ++ } ++ else { ++ sprintf(str, "Unable to remove a InfoFile header form '%s'.", bf->name); ++ setBrowStr(br, str); ++ bf->ftype = BF_ERROR; ++ } ++ } ++#endif ++ ++#ifdef HAVE_MGCSFX_AUTO ++ if (bf->ftype != BF_ERROR) { ++ if(filetype == RFT_MGCSFX){ ++ char tmpname[128]; ++ char *icom; ++ ++ if((icom = mgcsfx_auto_input_com(bf->name)) != NULL){ ++ sprintf(tmpname, "%s/xvmsautoXXXXXX", tmpdir); ++#ifdef USE_MKSTEMP ++ close(mkstemp(tmpname)); ++#else ++ mktemp(tmpname); ++#endif ++ SetISTR(ISTR_INFO, "Converting to known format by MgcSfx auto..."); ++ sprintf(str,"%s >%s", icom, tmpname); ++ }else goto ms_auto_no; ++ ++#ifndef VMS ++ if (system(str)) ++#else ++ if (!system(str)) ++#endif ++ { ++ sprintf(str, "Unable to convert '%s' by MgcSfx auto.", bf->name); ++ setBrowStr(br, str); ++ bf->ftype = BF_ERROR; ++ } else { ++ filetype = ReadFileType(tmpname); ++ if (strcmp(readname, bf->name)!=0) unlink(readname); ++ strncpy(readname, tmpname, sizeof(readname) - 1); ++ } ++ } ++ } ++ms_auto_no: ++#endif /* HAVE_MGCSFX_AUTO */ ++ + /* get rid of comments. don't need 'em */ + if (pinfo.comment) free(pinfo.comment); pinfo.comment = (char *) NULL; + +@@ -3470,6 +3813,9 @@ + else { + /* otherwise it's a known filetype... do the *hard* part now... */ + ++#ifdef VS_ADJUST ++ normaspect = defaspect; ++#endif + i = ReadPicFile(readname, filetype, &pinfo, 1); + KillPageFiles(pinfo.pagebname, pinfo.numpages); + +@@ -3489,7 +3835,7 @@ + } + + /* if we made an uncompressed file, we can rm it now */ +- if (readname != bf->name) unlink(readname); ++ if (strcmp(readname, bf->name)!=0) unlink(readname); + + + /* at this point either BF_ERROR, BF_UNKNOWN, BF_EXE or pic */ +@@ -3507,16 +3853,30 @@ + + /* compute size of icon (iwide,ihigh) */ + ++#ifdef VS_ADJUST ++ if (!vsadjust) normaspect = 1; ++ ++ wexpand = (double) (pinfo.w * normaspect) / (double) ISIZE_WIDE; ++#else + wexpand = (double) pinfo.w / (double) ISIZE_WIDE; ++#endif /* VS_ADJUST */ + hexpand = (double) pinfo.h / (double) ISIZE_HIGH; + + if (wexpand >= 1.0 || hexpand >= 1.0) { /* don't expand small icons */ + if (wexpand>hexpand) { ++#ifdef VS_ADJUST ++ iwide = (int) ((pinfo.w * normaspect) / wexpand + 0.5); ++#else + iwide = (int) (pinfo.w / wexpand + 0.5); ++#endif + ihigh = (int) (pinfo.h / wexpand + 0.5); + } + else { ++#ifdef VS_ADJUST ++ iwide = (int) ((pinfo.w * normaspect) / hexpand + 0.5); ++#else + iwide = (int) (pinfo.w / hexpand + 0.5); ++#endif + ihigh = (int) (pinfo.h / hexpand + 0.5); + } + } +@@ -3566,6 +3926,15 @@ + case RFT_XPM: strcat(str,"XPM file"); break; + case RFT_XWD: strcat(str,"XWD file"); break; + case RFT_FITS: strcat(str,"FITS file"); break; ++ case RFT_PNG: strcat(str,"PNG file"); break; ++ case RFT_ZX: strcat(str,"Spectrum SCREEN$"); break; /* [JCE] */ ++ case RFT_PCD: strcat(str,"PhotoCD file"); break; ++ case RFT_MAG: strcat(str,"MAG file"); break; ++ case RFT_MAKI: strcat(str,"MAKI file"); break; ++ case RFT_PIC: strcat(str,"PIC file"); break; ++ case RFT_PI: strcat(str,"PI file"); break; ++ case RFT_PIC2: strcat(str,"PIC2 file"); break; ++ case RFT_MGCSFX: strcat(str,"Magic Suffix file"); break; + default: strcat(str,"file of unknown type"); break; + } + +@@ -3669,6 +4038,10 @@ + + sprintf(thFname, "%s%s/%s", br->path, THUMBDIR, bf->name); + ++#ifdef AUTO_EXPAND ++ Dirtovd(thFname); ++#endif ++ + fp = fopen(thFname, "r"); + if (!fp) return; /* nope, it doesn't have one */ + +@@ -3784,6 +4157,11 @@ + + sprintf(thFname, "%s%s/%s", br->path, THUMBDIR, bf->name); + ++#ifdef AUTO_EXPAND ++ Dirtovd(thFname); ++#endif ++ ++ unlink(thFname); /* just in case there's already an unwritable one */ + fp = fopen(thFname, "w"); + if (!fp) { + sprintf(buf, "Can't create thumbnail file '%s': %s", thFname, +@@ -3848,15 +4226,30 @@ + + sprintf(thFname, "%s%s", br->path, THUMBDIRNAME); + ++#ifdef AUTO_EXPAND ++ Dirtovd(thFname); ++#endif ++ + i = stat(thFname, &st); + if (i) { /* failed, let's create it */ + sprintf(thFname, "%s.", br->path); ++#ifdef AUTO_EXPAND ++ Dirtovd(thFname); ++#endif + i = stat(thFname, &st); /* get permissions of parent dir */ + if (!i) perm = st.st_mode & 07777; + else perm = 0755; + + sprintf(thFname, "%s%s", br->path, THUMBDIRNAME); ++#ifdef AUTO_EXPAND ++ Dirtovd(thFname); ++# ifdef VIRTUAL_TD ++ if (mkdir(thFname, (mode_t) perm) < 0) ++ Mkvdir_force(thFname); ++# else + mkdir(thFname, (mode_t) perm); ++# endif ++#endif + } + } + +@@ -3898,7 +4291,7 @@ + for (i=0, bf=br->bfList; i<br->bfLen; i++, bf++) { + if (bf->ftype <= BF_FILE || bf->ftype >= BF_ERROR || bf->ftype==BF_EXE) { + +- /* ie, not a 'special' file */ ++ /* i.e., not a 'special' file */ + + int s1, s2; + char thfname[256]; +@@ -3912,10 +4305,9 @@ + sprintf(thfname, "%s/%s", THUMBDIR, bf->name); + s2 = stat(thfname, &thumbst); + +- if (s1 || s2 || filest.st_mtime > thumbst.st_mtime || +- filest.st_ctime > thumbst.st_ctime) { ++ if (s1 || s2 || filest.st_mtime > thumbst.st_mtime) { + /* either stat'ing the file or the thumbfile failed, or +- both stat's succeeded and the file has a newer mod or creation ++ both stat's succeeded and the file has a newer mod + time than the thumbnail file */ + + makeIconVisible(br, i); +@@ -3927,8 +4319,12 @@ + iconsBuilt++; + if (DEBUG) + fprintf(stderr,"icon made:fname='%s' thfname='%s' %d,%d,%ld,%ld\n", +- bf->name, thfname, s1,s2,filest.st_mtime,thumbst.st_mtime); ++ bf->name, thfname, s1, s2, ++ (long)filest.st_mtime, (long)thumbst.st_mtime); + } ++ } else if (filest.st_ctime > thumbst.st_ctime) { ++ /* update protections */ ++ chmod(thfname, (mode_t) (filest.st_mode & 07777)); + } + } + statcount++; +@@ -3963,7 +4359,11 @@ + sprintf(thfname, "%s/%s", THUMBDIR, dp->d_name); + if (stat(thfname, &thumbst)==0) { /* success */ + int tmp; ++#ifdef AUTO_EXPAND ++ tmp = stat2bf((u_int) thumbst.st_mode , thfname); ++#else + tmp = stat2bf((u_int) thumbst.st_mode); ++#endif + + if (tmp == BF_FILE) { /* a plain file */ + /* see if this thumbfile has an associated pic file */ +@@ -4042,6 +4442,15 @@ + static char *labels[] = { "\nOk", "\033Cancel" }; + struct stat st; + ++#ifdef AUTO_EXPAND ++ if (Isvdir(br->path)) { ++ sprintf(buf,"Sorry, you can't rename file in the virtual directory, '%s'", ++ br->path); ++ ErrPopUp(buf, "\nBummer!"); ++ return; ++ } ++#endif ++ + if (cdBrow(br)) return; + + /* find the selected file */ +@@ -4129,6 +4538,15 @@ + static char *labels[] = { "\nOk", "\033Cancel" }; + struct stat st; + ++#ifdef AUTO_EXPAND ++ if (Isvdir(br->path)) { ++ sprintf(buf,"Sorry, you can't mkdir in the virtual directory, '%s'", ++ br->path); ++ ErrPopUp(buf, "\nBummer!"); ++ return; ++ } ++#endif ++ + if (cdBrow(br)) return; + + buf[0] = '\0'; +@@ -4197,14 +4615,34 @@ + if (cdBrow(br)) return; /* prints its own error message */ + } + ++#ifdef AUTO_EXPAND ++ if (Chvdir(buf)) { ++#else + if (chdir(buf)) { ++#endif + sprintf(str,"Unable to cd to '%s'\n", buf); + setBrowStr(br, str); + XBell(theDisp, 50); + } + else { ++#ifdef AUTO_EXPAND ++ if (Isvdir(buf)) { ++ BTSetActive(&br->but[BR_DELETE], 0); ++ br->cmdMB.dim[BR_DELETE] = 1; ++ ++ BTSetActive(&br->but[BR_RENAME], 0); ++ br->cmdMB.dim[BR_RENAME] = 1; ++ ++ BTSetActive(&br->but[BR_MKDIR], 0); ++ br->cmdMB.dim[BR_MKDIR] = 1; ++ } else { ++ BTSetActive(&br->but[BR_MKDIR], 1); ++ br->cmdMB.dim[BR_MKDIR] = 0; ++ } ++#endif + scanDir(br); + SCSetVal(&(br->scrl), 0); /* reset to top on a chdir */ ++ restIconVisible(br); + } + } + +@@ -4229,6 +4667,15 @@ + char buf[512]; + static char *yesno[] = { "\004Delete", "\033Cancel" }; + ++#ifdef AUTO_EXPAND ++ if (Isvdir(br->path)) { ++ sprintf(buf,"Sorry, you can't delete file at the virtual directory, '%s'", ++ br->path); ++ ErrPopUp(buf, "\nBummer!"); ++ return; ++ } ++#endif ++ + if (!br->bfLen || !br->bfList || !br->numlit) return; + + if (cdBrow(br)) return; /* can't cd to this directory. screw it! */ +@@ -4251,7 +4698,11 @@ + for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) { + if (bf->lit) { + if (firstdel == -1) firstdel = i; +- if (bf->ftype == BF_DIR) numdirs++; ++ if (bf->ftype == BF_DIR ++#ifdef AUTO_EXPAND ++ && (!Isarchive(bf->name)) ++#endif ++ ) numdirs++; + else numfiles++; + } + } +@@ -4265,7 +4716,12 @@ + slen = strlen(buf); + + for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) { ++#ifdef AUTO_EXPAND ++ if (bf->lit && (bf->ftype != BF_DIR || Isarchive(bf->name))) { ++#else + if (bf->lit && bf->ftype != BF_DIR) { ++#endif ++ + if ( (slen + strlen(bf->name) + 1) > 256) { + strcat(buf,"..."); + break; +@@ -4277,7 +4733,7 @@ + } + } + +- i = PopUp(buf, yesno, 2); ++ i = PopUp(buf, yesno, COUNT(yesno)); + if (i) return; /* cancelled */ + } + +@@ -4290,7 +4746,11 @@ + slen = strlen(buf); + + for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) { ++#ifdef AUTO_EXPAND ++ if (bf->lit && (bf->ftype == BF_DIR || !Isarchive(bf->name))) { ++#else + if (bf->lit && bf->ftype == BF_DIR) { ++#endif + if ( (slen + strlen(bf->name) + 1) > 256) { + strcat(buf,"..."); + break; +@@ -4302,7 +4762,7 @@ + } + } + +- i = PopUp(buf, yesno, 2); ++ i = PopUp(buf, yesno, COUNT(yesno)); + if (i) return; /* cancelled */ + } + +@@ -4311,7 +4771,11 @@ + + for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) { + if (bf->lit) { +- if (bf->ftype == BF_DIR) rm_dir (br, bf->name); ++ if (bf->ftype == BF_DIR ++#ifdef AUTO_EXPAND ++ && !Isarchive(bf->name) ++#endif ++ ) rm_dir (br, bf->name); + else rm_file(br, bf->name); + } + } +@@ -4440,7 +4904,11 @@ + xv_getwd(orgDir, sizeof(orgDir)); + + sprintf(curDir, "%s%s", br->path, subdir); ++#ifdef AUTO_EXPAND ++ if (Chvdir(curDir)) { ++#else + if (chdir(curDir)) { ++#endif + char str[512]; + sprintf(str, "Unable to cd to '%s'\n", curDir); + setBrowStr(br, str); +@@ -4452,14 +4920,24 @@ + /* have we looped? */ + for (i=0; i<dirStackLen && strcmp(curDir, dirStack[i]); i++); + if (i<dirStackLen) { /* YES */ ++#ifdef AUTO_EXPAND ++ Chvdir(orgDir); ++#else + chdir(orgDir); ++#endif ++ restIconVisible(br); + return; + } + + sp = (char *) malloc((size_t) strlen(curDir) + 1); + if (!sp) { + setBrowStr(br, "malloc() error in recurseUpdate()\n"); ++#ifdef AUTO_EXPAND ++ Chvdir(orgDir); ++#else + chdir(orgDir); ++#endif ++ restIconVisible(br); + return; + } + +@@ -4494,7 +4972,12 @@ + + xv_getwd(curDir, sizeof(curDir)); + if (strcmp(orgDir, curDir)) { /* change back to orgdir */ ++#ifdef AUTO_EXPAND ++ Chvdir(orgDir); ++#else + chdir(orgDir); ++#endif ++ restIconVisible(br); + scanDir(br); + } + } +@@ -4518,6 +5001,13 @@ + setBrowStr(br, buf); + } + ++#ifdef AUTO_EXPAND ++ if (Rmvdir(name)) { ++ sprintf(buf, "fail to remove virturl directory: %s", name); ++ setBrowStr(br, buf); ++ } ++#endif ++ + /* try to delete a thumbnail file, as well. ignore errors */ + strcpy(buf1, name); /* tmp1 = leading path of name */ + tmp = (char *) rindex(buf1, '/'); +@@ -4586,7 +5076,14 @@ + goto done; + } + +- if (stat2bf((u_int) st.st_mode) == BF_DIR) { /* skip, for now */ ++#ifdef AUTO_EXPAND ++ if ((stat2bf((u_int) st.st_mode , rmdirPath) == BF_DIR) ++ && !Isarchive(rmdirPath)) /* skip, for now */ ++#else ++ ++ if (stat2bf((u_int) st.st_mode) == BF_DIR) /* skip, for now */ ++#endif ++ { + rmdirPath[oldpathlen] = '\0'; + continue; /* don't remove from list */ + } +@@ -4639,9 +5136,9 @@ + + static int overwrite; + #define OWRT_ASK 0 +-#define OWRT_NOASK 1 +-#define OWRT_CANCEL 2 +- ++#define OWRT_ALWAYS 1 ++#define OWRT_NEVER 2 ++#define OWRT_CANCEL 3 + + /*******************************************/ + static void dragFiles(srcBr, dstBr, srcpath, dstpath, dstdir, +@@ -4676,11 +5173,26 @@ + } + else if (strcmp(dstdir,".")!=0) sprintf(dstp, "%s%s/", dstpath, dstdir); + ++#ifdef AUTO_EXPAND ++ if (Isvdir(dstp)) { ++ sprintf(buf,"Sorry, you can't %s to the virtual directory, '%s'", ++ cpymode ? "copy" : "move", dstp); ++ ErrPopUp(buf, "\nBummer!"); ++ SetCursors(-1); ++ return; ++ } ++ if (Isvdir(srcpath)) ++ cpymode = 1; ++#endif ++ + + + /* if there is a thumbnail directory in 'srcpath', make one for dstpath */ + sprintf(src,"%s%s", srcpath, THUMBDIR); + dothumbs = 0; ++#ifdef AUTO_EXPAND ++ Dirtovd(src); ++#endif + if (stat(src, &st)==0) { + sprintf(dst,"%s%s", dstp, THUMBDIR); + mkdir(dst, st.st_mode & 07777); +@@ -4711,6 +5223,14 @@ + if (overwrite == OWRT_CANCEL) break; /* abort move */ + if (j==1) fail++; + ++#ifdef AUTO_EXPAND ++ if (!cpymode && j==0) ++ if (Movevdir(src,dst)) { ++ sprintf(buf, "fail to move virturl directory: %s", names[i]); ++ setBrowStr(srcBr, buf); ++ } ++#endif ++ + if (dothumbs && j==0) { + sprintf(src,"%s%s/%s", srcpath, THUMBDIR, names[i]); + sprintf(dst,"%s%s/%s", dstp, THUMBDIR, names[i]); +@@ -4748,6 +5268,15 @@ + } + + ++ if (!cpymode) { ++ /* clear all lit files in the source folder (as they've been moved) ++ note: this won't be the optimal behavior if any files failed to ++ move, but screw it, that's not going to happen too often... */ ++ for (i=0; i<srcBr->bfLen; i++) srcBr->bfList[i].lit = 0; ++ srcBr->numlit = 0; ++ } ++ ++ + /* clear all files in the destination folder */ + for (i=0; i<dstBr->bfLen; i++) { + dstBr->bfList[i].lit = 0; +@@ -4793,7 +5322,51 @@ + SetCursors(-1); + } + ++static int recursive_remove(dir) ++ char *dir; ++{ ++ DIR *dp = NULL; ++ struct dirent *di; ++ char name[MAXPATHLEN+1]; ++ ++ strncpy(name, dir, MAXPATHLEN); ++ name[MAXPATHLEN] = 0; ++ ++ if (name[strlen(name) - 1] == '/') ++ name[strlen(name) - 1] = 0; + ++ if ((dp = opendir(name)) == NULL) ++ goto err; ++ ++ while ((di = readdir(dp)) != NULL) { ++ char buf[MAXPATHLEN+1]; ++ struct stat st; ++ ++ if (!strcmp(di->d_name, ".") || !strcmp(di->d_name, "..")) ++ continue; ++ ++ snprintf(buf, MAXPATHLEN, "%s/%s", name, di->d_name); ++ ++ if (stat(buf, &st) < 0) ++ continue; ++ ++ if (S_ISDIR(st.st_mode)) { ++ if (recursive_remove(buf) < 0) ++ goto err; ++ } else ++ unlink(buf); ++ } ++ ++ if (rmdir(name) < 0) ++ goto err; ++ ++ closedir(dp); ++ return 0; ++ ++err: ++ if (dp) closedir(dp); ++ return -1; ++} + + /*************************************************/ + static int moveFile(src,dst) +@@ -4811,31 +5384,45 @@ + int i, srcdir, dstdir; + struct stat st; + char buf[512]; +- static char *owbuts[4] = { "\nOk", "dDon't ask", "nNo", "\033Cancel" }; ++ static char *owbuts[] = { "\nOk", "aAlways", "nNo", "NNever", "\033Cancel" }; + + if (DEBUG) fprintf(stderr,"moveFile %s %s\n", src, dst); + ++#ifdef AUTO_EXPAND ++ Dirtosubst(src); ++#endif ++ + if (stat(src, &st)) return 0; /* src doesn't exist, it would seem */ ++#ifdef AUTO_EXPAND ++ srcdir = (stat2bf((u_int) st.st_mode , src) == BF_DIR); ++#else + srcdir = (stat2bf((u_int) st.st_mode) == BF_DIR); ++#endif + + /* see if destination exists */ ++ + if (stat(dst, &st)==0) { ++ if (overwrite==OWRT_NEVER) return -1; ++#ifdef AUTO_EXPAND ++ dstdir = (stat2bf((u_int) st.st_mode , dst) == BF_DIR); ++#else + dstdir = (stat2bf((u_int) st.st_mode) == BF_DIR); ++#endif + + if (overwrite==OWRT_ASK) { +- sprintf(buf, "%s '%s' exists.\n\nOverwrite?", ++ snprintf(buf, sizeof(buf), "%s '%s' exists.\n\nOverwrite?", + dstdir ? "Directory" : "File", dst); +- i = PopUp(buf, owbuts, 4); +- +- if (i==1) overwrite = OWRT_NOASK; +- else if (i==2) return -1; +- else if (i==3) { overwrite = OWRT_CANCEL; return 1; } ++ switch (PopUp(buf, owbuts, COUNT(owbuts))) { ++ case 1: overwrite = OWRT_ALWAYS; break; ++ case 2: return -1; ++ case 3: overwrite = OWRT_NEVER; return -1; ++ case 4: overwrite = OWRT_CANCEL; return 1; ++ } + } + + if (dstdir) { + #ifndef VMS /* we don't delete directories in VMS */ +- sprintf(buf, "rm -rf %s", dst); +- if (system(buf)) { /* okay, so it's cheating... */ ++ if (recursive_remove(dst)) { /* okay, so it's cheating... */ + SetISTR(ISTR_WARNING, "Unable to remove directory %s", dst); + return 1; + } +@@ -4858,9 +5445,8 @@ + if (i == 0) { /* copied okay, kill the original */ + if (srcdir) { + #ifndef VMS /* we don't delete directories in VMS */ +- sprintf(buf, "rm -rf %s", src); +- if (system(buf)) { /* okay, so it's cheating... */ +- SetISTR(ISTR_WARNING, "Unable to remove directory %s", dst); ++ if (recursive_remove(src)) { /* okay, so it's cheating... */ ++ SetISTR(ISTR_WARNING, "Unable to remove directory %s", src); + return 1; + } + #endif /* VMS */ +@@ -4906,38 +5492,51 @@ + fall through: if dest doesn't exist, copy the directory, recurs */ + + +- int i, dstExists, srcdir, dstdir; ++ int dstExists, srcdir, dstdir; + struct stat srcSt, dstSt; + char buf[1024]; +- static char *owdiff[3] = { "\nOk", "nNo", "\033Cancel" }; +- static char *owsame[4] = { "\nOk", "dDon't Ask", "nNo", "\033Cancel" }; ++ static char *owdiff[] = { "\nOk", "nNo", "\033Cancel" }; ++ static char *owsame[] = { "\nOk", "aAlways", "nNo", "NNever", "\033Cancel" }; + + if (DEBUG) fprintf(stderr,"copyFile %s %s\n", src, dst); + ++#ifdef AUTO_EXPAND ++ Dirtosubst(src); ++#endif ++ + if (stat(src,&srcSt)) return 0; /* source doesn't exist, it would seem */ + + dstExists = (stat(dst, &dstSt)==0); + + if (dstExists) { /* ask about overwriting... */ +- srcdir = (stat2bf((u_int) srcSt.st_mode) == BF_DIR); +- dstdir = (stat2bf((u_int) dstSt.st_mode) == BF_DIR); ++#ifdef AUTO_EXPAND ++ srcdir = (stat2bf((u_int) srcSt.st_mode , src) == BF_DIR); ++ dstdir = (stat2bf((u_int) dstSt.st_mode , dst) == BF_DIR); ++#else ++ srcdir = (stat2bf((u_int) srcSt.st_mode) == BF_DIR); ++ dstdir = (stat2bf((u_int) dstSt.st_mode) == BF_DIR); ++#endif + + sprintf(buf, "%s '%s' already exists. Replace it with %s '%s'?", + (dstdir) ? "Directory" : "File", dst, + (srcdir) ? "contents of directory" : "file", src); + + if (srcdir == dstdir) { ++ if (overwrite==OWRT_NEVER) return -1; + if (overwrite==OWRT_ASK) { +- i = PopUp(buf, owsame, 4); +- if (i==1) overwrite = OWRT_NOASK; +- if (i==2) return -1; +- else if (i==3) { overwrite = OWRT_CANCEL; return 1; } ++ switch (PopUp(buf, owsame, COUNT(owsame))) { ++ case 1: overwrite = OWRT_ALWAYS; break; ++ case 2: return -1; ++ case 3: overwrite = OWRT_NEVER; return -1; ++ case 4: overwrite = OWRT_CANCEL; return 1; ++ } + } + } + else { /* one's a dir, the other's a file. *ALWAYS* ask! */ +- i = PopUp(buf, owdiff, 3); +- if (i==1) return -1; +- else if (i==2) { overwrite = OWRT_CANCEL; return 1; } ++ switch (PopUp(buf, owdiff, COUNT(owdiff))) { ++ case 1: return -1; ++ case 2: overwrite = OWRT_CANCEL; return 1; ++ } + } + + +@@ -5035,8 +5634,11 @@ + havedst = 1; + } + +- ++#ifdef AUTO_EXPAND ++ switch(stat2bf((u_int) srcSt.st_mode , cpDstPath)) { ++#else + switch(stat2bf((u_int) srcSt.st_mode)) { ++#endif + /* determine how to copy, by filetype */ + + /* NOTE: There is no S_IFLNK case here, since we're using 'stat()' and +@@ -5052,7 +5654,11 @@ + } + } + else { ++#ifdef AUTO_EXPAND ++ if (stat2bf((u_int) dstSt.st_mode , cpDstPath) != BF_DIR) { ++#else + if (stat2bf((u_int) dstSt.st_mode) != BF_DIR) { ++#endif + SetISTR(ISTR_WARNING,"%s: not a directory", cpDstPath); + copyerr++; + return; +@@ -5130,7 +5736,12 @@ + goto done; + } + +- if (stat2bf((u_int) srcSt.st_mode) == BF_DIR) { ++#ifdef AUTO_EXPAND ++ if (stat2bf((u_int) srcSt.st_mode , cpSrcPath) == BF_DIR) ++#else ++ if (stat2bf((u_int) srcSt.st_mode) == BF_DIR) ++#endif ++ { + cpSrcPath[oldsrclen] = '\0'; + continue; /* don't remove from list, just skip */ + } +@@ -5189,9 +5800,9 @@ + int exists; + /*****************************/ + { +- register int srcFd, dstFd, rcount, wcount, i; ++ register int srcFd, dstFd, rcount, wcount; + char buf[8192]; +- static char *owbuts[4] = { "\nOk", "dDon't Ask", "nNo", "\033Cancel" }; ++ static char *owbuts[] = { "\nOk", "aAlways", "nNo", "NNever", "\033Cancel" }; + + if (DEBUG) fprintf(stderr,"cp_file: src='%s', dst='%s'\n", + cpSrcPath, cpDstPath); +@@ -5203,13 +5814,15 @@ + } + + if (exists) { ++ if (overwrite==OWRT_NEVER) return; + if (overwrite==OWRT_ASK) { + sprintf(buf, "File '%s' exists.\n\nOverwrite?", cpDstPath); +- i = PopUp(buf, owbuts, 4); +- +- if (i==1) overwrite = OWRT_NOASK; +- else if (i==2) return; +- else if (i==3) { overwrite = OWRT_CANCEL; return; } ++ switch (PopUp(buf, owbuts, 4)) { ++ case 1: overwrite = OWRT_ALWAYS; break; ++ case 2: return; ++ case 3: overwrite = OWRT_NEVER; return; ++ case 4: overwrite = OWRT_CANCEL; return; ++ } + } + dstFd = open(cpDstPath, O_WRONLY|O_TRUNC, 0); + } +@@ -5303,8 +5916,14 @@ + + + /*********************************/ ++#ifdef AUTO_EXPAND ++static int stat2bf(uistmode, path) ++ u_int uistmode; ++ char *path; ++#else + static int stat2bf(uistmode) + u_int uistmode; ++#endif + { + /* given the 'st.st_mode' field from a successful stat(), returns + BF_FILE, BF_DIR, BF_BLK, BF_CHR, BF_FIFO, or BF_SOCK. Does *NOT* +@@ -5318,6 +5937,9 @@ + else if (S_ISBLK(stmode)) rv = BF_BLK; + else if (S_ISFIFO(stmode)) rv = BF_FIFO; + else if (S_ISSOCK(stmode)) rv = BF_SOCK; ++#ifdef AUTO_EXPAND ++ else if (Isarchive(path)) rv = BF_DIR; ++#endif + else rv = BF_FILE; + + return rv; +@@ -5418,4 +6040,56 @@ + } + + ++static IVIS *icon_vis_list = NULL; ++ ++/***************************************************************/ ++static void recIconVisible(name, icon) ++ char *name; ++ int icon; ++{ ++ IVIS *ptr, *prev = NULL; ++ ++ for (ptr = icon_vis_list; ptr; prev = ptr, ptr = ptr->next) { ++ if (!strcmp(ptr->name, name)) { ++ ptr->icon = icon; ++ return; ++ } ++ } ++ ++ ptr = calloc(sizeof(IVIS), 1); ++ if (!ptr) ++ return; ++ ++ ptr->name = strdup(name); + ++ if (!ptr->name) { ++ free(ptr); ++ return; ++ } ++ ++ if (!prev) { ++ icon_vis_list = ptr; ++ } else { ++ prev->next = ptr; ++ } ++ ++ ptr->next = NULL; ++ ptr->icon = icon; ++} ++ ++/***************************************************************/ ++static void restIconVisible(br) ++ BROWINFO *br; ++{ ++ IVIS *ptr; ++ ++ for (ptr = icon_vis_list; ptr; ptr = ptr->next) { ++ if (!strcmp(ptr->name, br->path)) { ++ if (ptr->icon >= 0) { ++ makeIconVisible(br, ptr->icon); ++ updateSel(br, ptr->icon, 0, 0); ++ } ++ return; ++ } ++ } ++} +diff -ruN xv-3.10a-bugfixes/xvctrl.c xv-3.10a-enhancements/xvctrl.c +--- xv-3.10a-bugfixes/xvctrl.c 2004-05-23 11:56:37.000000000 -0700 ++++ xv-3.10a-enhancements/xvctrl.c 2004-05-23 12:15:18.000000000 -0700 +@@ -104,7 +104,8 @@ + "Root: centered, warp", + "Root: centered, brick", + "Root: symmetrical tiled", +- "Root: symmetrical mirrored" }; ++ "Root: symmetrical mirrored", ++ "Root: upper left corner" }; + + static char *conv24MList[] = { "8-bit mode\t\2448", + "24-bit mode\t\2448", +diff -ruN xv-3.10a-bugfixes/xvdial.c xv-3.10a-enhancements/xvdial.c +--- xv-3.10a-bugfixes/xvdial.c 2004-05-16 18:01:57.000000000 -0700 ++++ xv-3.10a-enhancements/xvdial.c 2004-05-16 18:06:38.000000000 -0700 +@@ -41,20 +41,21 @@ + + + /* local functions */ +-static int whereInDial PARM((DIAL *, int, int)); +-static void drawArrow PARM((DIAL *)); +-static void drawValStr PARM((DIAL *)); +-static void drawButt PARM((DIAL *, int, int)); +-static int computeDialVal PARM((DIAL *, int, int)); +-static void dimDial PARM((DIAL *)); ++static int whereInDial PARM((DIAL *, int, int)); ++static void drawArrow PARM((DIAL *)); ++static void drawValStr PARM((DIAL *)); ++static void drawButt PARM((DIAL *, int, int)); ++static double computeDialVal PARM((DIAL *, int, int)); ++static void dimDial PARM((DIAL *)); + + + /***************************************************/ +-void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, page, ++void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, inc, page, + fg, bg, hi, lo, title, units) + DIAL *dp; + Window parent; +-int x,y,w,h,minv,maxv,curv,page; ++int x,y,w,h; ++double minv,maxv,curv,inc,page; + unsigned long fg,bg,hi,lo; + char *title, *units; + { +@@ -98,18 +99,18 @@ + 1,fg,bg); + if (!dp->win) FatalError("can't create dial window"); + +- DSetRange(dp, minv, maxv, curv, page); ++ DSetRange(dp, minv, maxv, curv, inc, page); + XSelectInput(theDisp, dp->win, ExposureMask | ButtonPressMask); + } + + + /***************************************************/ +-void DSetRange(dp, minv, maxv, curv, page) +-DIAL *dp; +-int minv, maxv, curv, page; ++void DSetRange(dp, minv, maxv, curv, inc, page) ++DIAL *dp; ++double minv, maxv, curv, inc, page; + { + if (maxv<minv) maxv=minv; +- dp->min = minv; dp->max = maxv; dp->page = page; ++ dp->min = minv; dp->max = maxv; dp->inc = inc; dp->page = page; + dp->active = (minv < maxv); + + DSetVal(dp, curv); +@@ -118,8 +119,8 @@ + + /***************************************************/ + void DSetVal(dp, curv) +-DIAL *dp; +-int curv; ++DIAL *dp; ++double curv; + { + RANGE(curv, dp->min, dp->max); /* make sure curv is in-range */ + +@@ -129,7 +130,7 @@ + XSetForeground(theDisp, theGC, dp->bg); + drawArrow(dp); + +- dp->val = curv; ++ dp->val = (double)((int)(curv / dp->inc + (curv > 0 ? 0.5 : -0.5))) * dp->inc; + + /* draw new arrow and string */ + XSetForeground(theDisp, theGC, dp->fg); +@@ -202,7 +203,8 @@ + int mx,my; + { + Window rW,cW; +- int rx,ry, x,y, ipos, pos, lit, i, origval; ++ int rx, ry, x, y, ipos, pos, lit; ++ double origval; + unsigned int mask; + + lit = 0; +@@ -224,9 +226,9 @@ + if (ipos != INDIAL) { + drawButt(dp, ipos, 1); + switch (ipos) { +- case INCW1: if (dp->val < dp->max) DSetVal(dp, dp->val+1); break; ++ case INCW1: if (dp->val < dp->max) DSetVal(dp, dp->val+dp->inc); break; + case INCW2: if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page); break; +- case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1); break; ++ case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->inc); break; + case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page); break; + } + if (dp->drawobj != NULL) (dp->drawobj)(); +@@ -235,8 +237,9 @@ + } + + else { +- i = computeDialVal(dp, mx, my); +- DSetVal(dp, i); ++ double v; ++ v = computeDialVal(dp, mx, my); ++ DSetVal(dp, v); + if (dp->drawobj != NULL) (dp->drawobj)(); + } + +@@ -246,11 +249,11 @@ + if (!(mask & Button1Mask)) break; /* button released */ + + if (ipos == INDIAL) { +- int j; +- i = computeDialVal(dp, x, y); +- j = dp->val; +- DSetVal(dp, i); +- if (j != dp->val) { ++ double v, w; ++ v = computeDialVal(dp, x, y); ++ w = dp->val; ++ DSetVal(dp, v); ++ if (w != dp->val) { + /* track whatever dial controls */ + if (dp->drawobj != NULL) (dp->drawobj)(); + } +@@ -266,11 +269,11 @@ + + if (lit) { + switch (ipos) { +- case INCW1: if (dp->val < dp->max) DSetVal(dp, dp->val+1); ++ case INCW1: if (dp->val < dp->max) DSetVal(dp, dp->val+dp->inc); + break; + case INCW2: if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page); + break; +- case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1); ++ case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->inc); + break; + case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page); + break; +@@ -320,19 +323,20 @@ + static void drawArrow(dp) + DIAL *dp; + { +- int i, rad, cx, cy; ++ int rad, cx, cy; ++ double v; + XPoint arrow[4]; + + rad = dp->rad; cx = dp->cx; cy = dp->cy; + + /* map pos (range minv..maxv) into degrees (range 240..-60) */ +- i = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min); +- arrow[0].x = cx + (int) ((double) rad * .80 * cos(i * DEG2RAD)); +- arrow[0].y = cy - (int) ((double) rad * .80 * sin(i * DEG2RAD)); +- arrow[1].x = cx + (int) ((double) rad * .33 * cos((i+160) * DEG2RAD)); +- arrow[1].y = cy - (int) ((double) rad * .33 * sin((i+160) * DEG2RAD)); +- arrow[2].x = cx + (int) ((double) rad * .33 * cos((i-160) * DEG2RAD)); +- arrow[2].y = cy - (int) ((double) rad * .33 * sin((i-160) * DEG2RAD)); ++ v = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min); ++ arrow[0].x = cx + (int) ((double) rad * .80 * cos(v * DEG2RAD)); ++ arrow[0].y = cy - (int) ((double) rad * .80 * sin(v * DEG2RAD)); ++ arrow[1].x = cx + (int) ((double) rad * .33 * cos((v+160) * DEG2RAD)); ++ arrow[1].y = cy - (int) ((double) rad * .33 * sin((v+160) * DEG2RAD)); ++ arrow[2].x = cx + (int) ((double) rad * .33 * cos((v-160) * DEG2RAD)); ++ arrow[2].y = cy - (int) ((double) rad * .33 * sin((v-160) * DEG2RAD)); + arrow[3].x = arrow[0].x; + arrow[3].y = arrow[0].y; + XDrawLines(theDisp, dp->win, theGC, arrow, 4, CoordModeOrigin); +@@ -343,23 +347,37 @@ + static void drawValStr(dp) + DIAL *dp; + { +- int i, x1, x2; ++ int tot, i, x1, x2; + char foo[60], foo1[60]; + + /* compute longest string necessary so we can right-align this thing */ +- sprintf(foo,"%d",dp->min); x1 = strlen(foo); +- sprintf(foo,"%d",dp->max); x2 = strlen(foo); ++ sprintf(foo,"%d",(int)dp->min); x1 = strlen(foo); ++ sprintf(foo,"%d",(int)dp->max); x2 = strlen(foo); + if (dp->min < 0 && dp->max > 0) x2++; /* put '+' at beginning */ + i = x1; if (x2>x1) i = x2; + if (dp->units) i += strlen(dp->units); + +- if (dp->min < 0 && dp->max > 0) sprintf(foo,"%+d", dp->val); +- else sprintf(foo,"%d", dp->val); ++ sprintf(foo,"%g",dp->inc); /* space for decimal values */ ++ tot = i + strlen(foo) - 1; /* Take away the 0 from the beginning */ ++ ++ if (dp->min < 0.0 && dp->max > 0.0) sprintf(foo,"%+g", dp->val); ++ else sprintf(foo,"%g", dp->val); ++ ++ if (dp->inc < 1.0) ++ { ++ int j; ++ ++ if (dp->val == (double)((int)dp->val)) ++ strcat(foo,"."); ++ ++ for (j = strlen(foo); j < tot; j++) ++ strcat(foo,"0"); ++ } + + if (dp->units) strcat(foo,dp->units); + foo1[0] = '\0'; + if (strlen(foo) < (size_t) i) { +- for (i = i - strlen(foo); i>0; i--) strcat(foo1," "); ++ for (i-=strlen(foo);i>0;i--) strcat(foo1," "); + } + strcat(foo1, foo); + +@@ -411,12 +429,13 @@ + + + /***************************************************/ +-static int computeDialVal(dp, x, y) ++static double computeDialVal(dp, x, y) + DIAL *dp; + int x, y; + { +- int dx, dy, val; +- double angle; ++ int dx, dy; ++ ++ double angle, val; + + /* compute dx, dy (distance from cx, cy). Note: +dy is *up* */ + dx = x - dp->cx; dy = dp->cy - y; +@@ -436,8 +455,10 @@ + if (angle > 270.0) angle -= 360.0; + if (angle < -90.0) angle += 360.0; + +- val = (int) ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min; ++ val = ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min; + ++ /* round value to be an even multiple of dp->inc */ ++ val = (double)((int)(val / dp->inc + 0.5)) * dp->inc; + return val; + } + +diff -ruN xv-3.10a-bugfixes/xvdir.c xv-3.10a-enhancements/xvdir.c +--- xv-3.10a-bugfixes/xvdir.c 2005-03-20 18:38:30.000000000 -0800 ++++ xv-3.10a-enhancements/xvdir.c 2005-04-25 22:24:28.000000000 -0700 +@@ -62,6 +62,9 @@ + #ifdef HAVE_TIFF + "TIFF", + #endif ++#ifdef HAVE_PNG ++ "PNG", ++#endif + "PostScript", + "PBM/PGM/PPM (raw)", + "PBM/PGM/PPM (ascii)", +@@ -73,9 +76,32 @@ + "Targa (24-bit)", + "FITS", + "PM", ++ "Spectrum SCREEN$", /* [JCE] */ ++ "WBMP", ++#ifdef HAVE_MAG ++ "MAG", ++#endif ++#ifdef HAVE_PIC ++ "PIC", ++#endif ++#ifdef HAVE_MAKI ++ "MAKI (640x400 only)", ++#endif ++#ifdef HAVE_PI ++ "PI", ++#endif ++#ifdef HAVE_PIC2 ++ "PIC2", ++#endif ++#ifdef HAVE_MGCSFX ++ "MgcSfx", ++#endif + MBSEP, + "Filename List"}; + ++#ifdef HAVE_PIC2 ++extern int PIC2SaveParams PARM((char *, int)); ++#endif + + static void arrangeButts PARM((int)); + static void RedrawDList PARM((int, SCRL *)); +@@ -570,7 +596,11 @@ + } + #endif + ++#ifdef AUTO_EXPAND ++ if (Chvdir(tmppath)) { ++#else + if (chdir(tmppath)) { ++#endif + char str[512]; + sprintf(str,"Unable to cd to '%s'\n", tmppath); + *trunc_point = '/'; /* restore the path */ +@@ -635,7 +665,11 @@ + xv_getwd(path, sizeof(path)); + #endif + ++#ifdef AUTO_EXPAND ++ if (Chvdir(path)) { ++#else + if (chdir(path)) { ++#endif + ErrPopUp("Current load/save directory seems to have gone away!", + "\nYikes!"); + #ifdef apollo +@@ -643,7 +677,11 @@ + #else + strcpy(path,"/"); + #endif ++#ifdef AUTO_EXPAND ++ Chvdir(path); ++#else + chdir(path); ++#endif + } + + changedDir = strcmp(path, oldpath); +@@ -748,6 +786,9 @@ + else if (S_ISFIFO(ftype)) fnames[i][0] = C_FIFO; + else if (S_ISSOCK(ftype)) fnames[i][0] = C_SOCK; + else if (fnames[i][0] == C_REG && (mode&0111)) fnames[i][0] = C_EXE; ++#ifdef AUTO_EXPAND ++ else if (Isarchive(fnames[i]+1)) fnames[i][0] = C_DIR; ++#endif + } + else { + /* fprintf(stderr,"problems 'stat-ing' files\n");*/ +@@ -847,7 +888,7 @@ + scrollToFileName(); + } + +- else if (c=='\010' || c=='\177') { /* BS or DEL */ ++ else if (c=='\010') { /* BS */ + if (curPos==0) return(-1); /* at beginning of str */ + xvbcopy(&filename[curPos], &filename[curPos-1], (size_t) (len-curPos+1)); + curPos--; +@@ -872,7 +913,7 @@ + curPos = len; + } + +- else if (c=='\004') { /* ^D: delete character at curPos */ ++ else if (c=='\004' || c=='\177') { /* ^D or DEL: delete character at curPos */ + if (curPos==len) return(-1); + xvbcopy(&filename[curPos+1], &filename[curPos], (size_t) (len-curPos)); + } +@@ -1055,6 +1096,25 @@ + + fullname = GetDirFullName(); + ++#ifdef AUTO_EXPAND ++ { ++ char path[MAXPATHLEN]; ++ ++ GetDirPath(path); ++ Mkvdir(path); ++ if ((i = Isvdir(fullname)) & 01) { ++ char buf[128]; ++ sprintf(buf, ++ "Sorry, you can't save file in the virtual directory, '%s'", ++ path); ++ ErrPopUp(buf, "\nBummer!"); ++ return -1; ++ } ++ if (i & 06) ++ Rmvdir(fullname); ++ } ++#endif ++ + fmt = MBWhich(&fmtMB); + col = MBWhich(&colMB); + +@@ -1116,7 +1176,34 @@ + } + #endif + ++#ifdef HAVE_PNG ++ else if (fmt == F_PNG) { /* PNG */ ++ PNGSaveParams(fullname, col); ++ PNGDialog(1); /* open PNG Dialog box */ ++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]); ++ return 0; /* always 'succeeds' */ ++ } ++#endif ++ ++#ifdef HAVE_PIC2 ++ else if (fmt == F_PIC2) { /* PIC2 */ ++ if (PIC2SaveParams(fullname, col) < 0) ++ return 0; ++ PIC2Dialog(1); /* open PIC2 Dialog box */ ++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]); ++ return 0; /* always 'succeeds' */ ++ } ++#endif /* HAVE_PIC2 */ + ++#ifdef HAVE_MGCSFX ++ else if (fmt == F_MGCSFX) { /* MGCSFX */ ++ if (MGCSFXSaveParams(fullname, col) < 0) ++ return 0; ++ MGCSFXDialog(1); /* open MGCSFX Dialog box */ ++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]); ++ return 0; /* always 'succeeds' */ ++ } ++#endif /* HAVE_MGCSFX */ + + + WaitCursor(); +@@ -1164,6 +1251,10 @@ + rv = WriteBMP (fp, thepic, ptype, w, h, rp, gp, bp, nc, col); + break; + ++ case F_WBMP: ++ rv = WriteWBMP (fp, thepic, ptype, w, h, rp, gp, bp, nc, col); ++ break; ++ + case F_IRIS: + rv = WriteIRIS (fp, thepic, ptype, w, h, rp, gp, bp, nc, col); + break; +@@ -1181,6 +1272,35 @@ + rv = WriteFITS (fp, thepic, ptype, w, h, rp, gp, bp, nc, col, + picComments); + break; ++ ++ case F_ZX: /* [JCE] Spectrum SCREEN$ */ ++ rv = WriteZX (fp, thepic, ptype, w, h, rp, gp, bp, nc, col, ++ picComments); ++ break; ++#ifdef HAVE_MAG ++ case F_MAG: ++ rv = WriteMAG (fp, thepic, ptype, w, h, rp, gp, bp, nc, col, ++ picComments); ++ break; ++#endif /* HAVE_MAG */ ++#ifdef HAVE_PIC ++ case F_PIC: ++ rv = WritePIC (fp, thepic, ptype, w, h, rp, gp, bp, nc, col, ++ picComments); ++ break; ++#endif /* HAVE_PIC */ ++#ifdef HAVE_MAKI ++ case F_MAKI: ++ rv = WriteMAKI (fp, thepic, ptype, w, h, rp, gp, bp, nc, col); ++ break; ++#endif /* HAVE_MAKI */ ++ ++#ifdef HAVE_PI ++ case F_PI: ++ rv = WritePi (fp, thepic, ptype, w, h, rp, gp, bp, nc, col, ++ picComments); ++ break; ++#endif /* HAVE_PI */ + } + + +@@ -1310,7 +1430,8 @@ + + else if (group == F_FORMAT) { + MBSelect(&fmtMB, bnum); +- if (MBWhich(&fmtMB) == F_XBM) { /* turn off all but B/W */ ++ if (MBWhich(&fmtMB) == F_XBM || ++ MBWhich(&fmtMB) == F_WBMP) { /* turn off all but B/W */ + colMB.dim[F_FULLCOLOR] = 1; + colMB.dim[F_GREYSCALE] = 1; + colMB.dim[F_BWDITHER] = 0; +@@ -1389,14 +1510,29 @@ + (strcmp(lowsuf,"eps" )==0) || + (strcmp(lowsuf,"rgb" )==0) || + (strcmp(lowsuf,"tga" )==0) || +- (strcmp(lowsuf,"xpm" )==0) || + (strcmp(lowsuf,"fits")==0) || + (strcmp(lowsuf,"fts" )==0) || ++#ifdef HAVE_JPEG + (strcmp(lowsuf,"jpg" )==0) || + (strcmp(lowsuf,"jpeg")==0) || + (strcmp(lowsuf,"jfif")==0) || ++#endif ++#ifdef HAVE_TIFF + (strcmp(lowsuf,"tif" )==0) || +- (strcmp(lowsuf,"tiff")==0)) { ++ (strcmp(lowsuf,"tiff")==0) || ++#endif ++#ifdef HAVE_PNG ++ (strcmp(lowsuf,"png" )==0) || ++#endif ++ (strcmp(lowsuf,"wbmp")==0) || ++ (strcmp(lowsuf,"xpm" )==0) || ++ (strcmp(lowsuf,"tiff")==0) || ++ (strcmp(lowsuf,"mag" )==0) || ++ (strcmp(lowsuf,"pic" )==0) || ++ (strcmp(lowsuf,"mki" )==0) || ++ (strcmp(lowsuf,"pi" )==0) || ++ (strcmp(lowsuf,"p2" )==0) || ++ (strcmp(lowsuf,"pcd" )==0)) { + + /* found one. set lowsuf = to the new suffix, and tack on to filename */ + +@@ -1419,6 +1555,7 @@ + case F_XBM: strcpy(lowsuf,"xbm"); break; + case F_SUNRAS: strcpy(lowsuf,"ras"); break; + case F_BMP: strcpy(lowsuf,"bmp"); break; ++ case F_WBMP: strcpy(lowsuf,"wbmp"); break; + case F_PS: strcpy(lowsuf,"ps"); break; + case F_IRIS: strcpy(lowsuf,"rgb"); break; + case F_TARGA: strcpy(lowsuf,"tga"); break; +@@ -1432,8 +1569,33 @@ + #ifdef HAVE_TIFF + case F_TIFF: strcpy(lowsuf,"tif"); break; + #endif ++ ++#ifdef HAVE_PNG ++ case F_PNG: strcpy(lowsuf,"png"); break; ++#endif ++ ++#ifdef HAVE_MAG ++ case F_MAG: strcpy(lowsuf,"mag"); break; ++#endif ++ ++#ifdef HAVE_PIC ++ case F_PIC: strcpy(lowsuf,"pic"); break; ++#endif ++ ++#ifdef HAVE_MAKI ++ case F_MAKI: strcpy(lowsuf,"mki"); break; ++#endif ++ ++#ifdef HAVE_PI ++ case F_PI: strcpy(lowsuf,"pi"); break; ++#endif ++ ++#ifdef HAVE_PIC2 ++ case F_PIC2: strcpy(lowsuf,"p2"); break; ++#endif + } + ++ + if (allcaps) { /* upper-caseify lowsuf */ + for (sp=lowsuf; *sp; sp++) + *sp = (islower(*sp)) ? toupper(*sp) : *sp; +@@ -1499,6 +1661,11 @@ + } + #endif + ++#ifdef AUTO_EXPAND ++ Mkvdir(newpath); ++ Dirtovd(newpath); ++#endif ++ + if (stat(newpath, &st)==0) { + int isdir; + +@@ -1596,7 +1763,11 @@ + dopipe = 0; + + /* make sure we're in the correct directory */ ++#ifdef AUTO_EXPAND ++ if (strlen(path)) Chvdir(path); ++#else + if (strlen(path)) chdir(path); ++#endif + + if (ISPIPE(filename[0])) { /* do piping */ + /* make up some bogus temp file to put this in */ +@@ -2002,7 +2173,7 @@ + if (stat(namelist[curname], &origStat)==0) { + haveStat = 1; + if (DEBUG) fprintf(stderr," origStat.size=%ld, origStat.mtime=%ld\n", +- origStat.st_size, origStat.st_mtime); ++ (long)origStat.st_size, (long)origStat.st_mtime); + } + } + } +@@ -2027,7 +2198,7 @@ + + if (stat(namelist[curname], &st)==0) { + if (DEBUG) fprintf(stderr," st.size=%ld, st.mtime=%ld\n", +- st.st_size, st.st_mtime); ++ (long)st.st_size, (long)st.st_mtime); + + if ((st.st_size == origStat.st_size) && + (st.st_mtime == origStat.st_mtime)) return 0; /* no change */ +@@ -2080,3 +2251,164 @@ + } + + ++#ifdef HAVE_PIC2 ++/**** Stuff for PIC2Dialog box ****/ ++FILE *pic2_OpenOutFile(filename, append) ++char *filename; ++int *append; ++{ ++ /* opens file for output. does various error handling bits. Returns ++ an open file pointer if success, NULL if failure */ ++ ++ FILE *fp = NULL; ++ struct stat st; ++ ++ if (!filename || filename[0] == '\0') ++ return (NULL); ++ strcpy(outFName, filename); ++ dopipe = 0; ++ ++ /* make sure we're in the correct directory */ ++#ifdef AUTO_EXPAND ++ if (strlen(path)) Chvdir(path); ++#else ++ if (strlen(path)) chdir(path); ++#endif ++ ++ if (ISPIPE(filename[0])) { /* do piping */ ++ /* make up some bogus temp file to put this in */ ++#ifndef VMS ++ sprintf(outFName, "%s/xvXXXXXX", tmpdir); ++#else ++ strcpy(outFName, "[]xvXXXXXX.lis"); ++#endif ++#ifdef USE_MKSTEMP ++ fp = fdopen(mkstemp(outFName), "w"); ++#else ++ mktemp(outFName); ++#endif ++ dopipe = 1; ++ } ++ ++ ++ /* see if file exists (i.e., we're overwriting) */ ++ *append = 0; ++#ifdef USE_MKSTEMP ++ if (!dopipe) ++#endif ++ if (stat(outFName, &st)==0) { /* stat succeeded, file must exist */ ++ if (ReadFileType(outFName) != RFT_PIC2) { ++ static char *foo[] = { "\nOk", "\033Cancel" }; ++ char str[512]; ++ ++ sprintf(str,"Overwrite existing file '%s'?", outFName); ++ if (PopUp(str, foo, 2)) ++ return (NULL); ++ } else { ++ static char *foo[] = { "\nOk", "\033Cancel" }; ++ char str[512]; ++ ++ sprintf(str,"Append to existing file '%s'?", outFName); ++ if (PopUp(str, foo, 2)) { ++ sprintf(str,"Overwrite existing file '%s'?", outFName); ++ if (PopUp(str, foo, 2)) ++ return (NULL); ++ } else ++ *append = 1; ++ } ++ } ++ ++ /* Open file */ ++#ifdef USE_MKSTEMP ++ if (!dopipe) ++#endif ++ fp = *append ? fopen(outFName, "r+") : fopen(outFName, "w"); ++ if (!fp) { ++ char str[512]; ++ sprintf(str,"Can't write file '%s'\n\n %s.",outFName, ERRSTR(errno)); ++ ErrPopUp(str, "\nBummer"); ++ return (NULL); ++ } ++ ++ return (fp); ++} ++ ++ ++/***************************************/ ++void pic2_KillNullFile(fp) ++FILE *fp; ++{ ++ fseek(fp, (size_t) 0, SEEK_END); ++ if (ftell(fp) > 0) { ++ fclose(fp); ++ return; ++ } else { ++ fclose(fp); ++ unlink(outFName); ++ return; ++ } ++} ++#endif /* HAVE_PIC2 */ ++ ++ ++#ifdef HAVE_MGCSFX ++/**** Stuff for MGCSFX Dialog box ****/ ++/***************************************/ ++int OpenOutFileDesc(filename) ++ char *filename; ++{ ++ /* opens file for output. does various error handling bits. Returns ++ an open file pointer if success, NULL if failure */ ++ ++ int fd; ++ struct stat st; ++ ++ if (!filename || filename[0] == '\0') return -1; ++ strcpy(outFName, filename); ++ dopipe = 0; ++ ++ /* make sure we're in the correct directory */ ++#ifdef AUTO_EXPAND ++ if (strlen(path)) Chvdir(path); ++#else ++ if (strlen(path)) chdir(path); ++#endif ++ ++ if (ISPIPE(filename[0])) { /* do piping */ ++ /* make up some bogus temp file to put this in */ ++#ifndef VMS ++ sprintf(outFName, "%s/xvXXXXXX", tmpdir); ++#else ++ strcpy(outFName, "[]xvXXXXXX.lis"); ++#endif ++#ifdef USE_MKSTEMP ++ close(mkstemp(outFName)); ++#else ++ mktemp(outFName); ++#endif ++ dopipe = 1; ++ } ++ ++ ++ /* if didn't just create it, see if file exists (i.e., we're overwriting) */ ++ if (!dopipe && stat(outFName, &st)==0) { /* stat succeeded, file exists */ ++ static char *foo[] = { "\nOk", "\033Cancel" }; ++ char str[512]; ++ ++ sprintf(str,"Overwrite existing file '%s'?", outFName); ++ if (PopUp(str, foo, 2)) return -1; ++ } ++ ++ ++ /* Open file */ ++ fd = open(outFName, O_WRONLY | O_CREAT | O_TRUNC, (0644)); ++ if (fd < 0) { ++ char str[512]; ++ sprintf(str,"Can't write file '%s'\n\n %s.", outFName, ERRSTR(errno)); ++ ErrPopUp(str, "\nBummer"); ++ return -1; ++ } ++ ++ return fd; ++} ++#endif /* HAVE_MGCSFX */ +diff -ruN xv-3.10a-bugfixes/xvevent.c xv-3.10a-enhancements/xvevent.c +--- xv-3.10a-bugfixes/xvevent.c 2004-05-16 18:02:03.000000000 -0700 ++++ xv-3.10a-enhancements/xvevent.c 2005-05-01 09:33:38.000000000 -0700 +@@ -64,6 +64,8 @@ + + static void annotatePic PARM((void)); + ++static int debkludge_offx; ++static int debkludge_offy; + + /****************/ + int EventLoop() +@@ -71,13 +73,25 @@ + { + XEvent event; + int retval,done,waiting; +- time_t orgtime, curtime; ++#ifdef USE_TICKS ++ clock_t waitsec_ticks=0L, orgtime_ticks=0L, curtime_ticks; ++ clock_t elapsed_ticks=0L, remaining_interval; ++#else ++ time_t orgtime=0L, curtime; ++#endif + + + #ifndef NOSIGNAL + signal(SIGQUIT, onInterrupt); + #endif + ++ if (startGrab == 1) { ++ startGrab = 2; ++ FakeButtonPress(&but[BGRAB]); ++ FakeKeyPress(ctrlW, XK_Return); ++ return(1); ++ } ++ + /* note: there's no special event handling if we're using the root window. + if we're using the root window, we will recieve NO events for mainW */ + +@@ -100,18 +114,24 @@ + + while (!done) { + +- if (waitsec > -1 && canstartwait && !waiting && XPending(theDisp)==0) { ++ if (waitsec >= 0.0 && canstartwait && !waiting && XPending(theDisp)==0) { + /* we wanna wait, we can wait, we haven't started waiting yet, and + all pending events (ie, drawing the image the first time) + have been dealt with: START WAITING */ +- time((time_t *) &orgtime); ++#ifdef USE_TICKS ++ waitsec_ticks = (clock_t)(waitsec * CLK_TCK); ++ orgtime_ticks = times(NULL); /* unclear if NULL valid, but OK on Linux */ ++#else ++ orgtime = time(NULL); ++#endif + waiting = 1; + } + + + /* if there's an XEvent pending *or* we're not doing anything + in real-time (polling, flashing the selection, etc.) get next event */ +- if ((waitsec==-1 && !polling && !HaveSelection()) || XPending(theDisp)>0) { ++ if ((waitsec<0.0 && !polling && !HaveSelection()) || XPending(theDisp)>0) ++ { + XNextEvent(theDisp, &event); + retval = HandleEvent(&event,&done); + } +@@ -121,7 +141,7 @@ + DrawSelection(0); + DrawSelection(1); + XFlush(theDisp); +- Timer(200); ++ Timer(200); /* milliseconds */ + } + + if (polling) { +@@ -129,13 +149,32 @@ + else if (!XPending(theDisp)) sleep(1); + } + +- if (waitsec>-1 && waiting) { +- time((time_t *) &curtime); +- if (curtime - orgtime < waitsec) sleep(1); +- else { +- if (waitloop) return NEXTLOOP; +- else return NEXTQUIT; +- } ++ if (waitsec>=0.0 && waiting) { ++#ifdef USE_TICKS ++ curtime_ticks = times(NULL); /* value in ticks */ ++ if (curtime_ticks < orgtime_ticks) { ++ /* clock ticks rolled over: need to correct for that (i.e., ++ * curtime_ticks is presumably quite small, while orgtime_ticks ++ * should be close to LONG_MAX, so do math accordingly--any way ++ * to check whether clock_t is *not* a signed long?) */ ++ elapsed_ticks = curtime_ticks + (LONG_MAX - orgtime_ticks); ++ } else ++ elapsed_ticks = curtime_ticks - orgtime_ticks; ++ remaining_interval = waitsec_ticks - elapsed_ticks; ++ if (remaining_interval >= (clock_t)(1 * CLK_TCK)) ++ sleep(1); ++ else { ++ /* less than one second remaining: do delay in msec, then return */ ++ Timer((remaining_interval * 1000L) / CLK_TCK); /* can't overflow */ ++ return waitloop? NEXTLOOP : NEXTQUIT; ++ } ++#else ++ curtime = time(NULL); /* value in seconds */ ++ if (curtime - orgtime < (time_t)waitsec) ++ sleep(1); ++ else ++ return waitloop? NEXTLOOP : NEXTQUIT; ++#endif + } + } + } /* while (!done) */ +@@ -154,7 +193,24 @@ + int *donep; + { + static int wasInfoUp=0, wasCtrlUp=0, wasDirUp=0, wasGamUp=0, wasPsUp=0; +- static int wasJpegUp=0, wasTiffUp=0; ++#ifdef HAVE_JPEG ++ static int wasJpegUp=0; ++#endif ++#ifdef HAVE_TIFF ++ static int wasTiffUp=0; ++#endif ++#ifdef HAVE_PNG ++ static int wasPngUp=0; ++#endif ++#ifdef HAVE_PCD ++ static int wasPcdUp=0; ++#endif ++#ifdef HAVE_PIC2 ++ static int wasPic2Up=0; ++#endif ++#ifdef HAVE_MGCSFX ++ static int wasMgcSfxUp=0; ++#endif + + static int mainWKludge=0; /* force first mainW expose after a mainW config + to redraw all of mainW */ +@@ -233,6 +289,28 @@ + if (TIFFCheckEvent(event)) break; /* event has been processed */ + #endif + ++#ifdef HAVE_PNG ++ if (PNGCheckEvent (event)) break; /* event has been processed */ ++#endif ++ ++ if (PCDCheckEvent(event)) break; /* event has been processed */ ++ ++#ifdef HAVE_PIC2 ++ if (PIC2CheckEvent(event)) break; /* event has been processed */ ++#endif ++ ++#ifdef HAVE_PCD ++ if (PCDCheckEvent (event)) break; /* event has been processed */ ++#endif ++ ++#ifdef HAVE_MGCSFX ++ if (MGCSFXCheckEvent(event)) break; /* event has been processed */ ++#endif ++ ++#ifdef TV_MULTILINGUAL ++ if (CharsetCheckEvent(event)) break; /* event has been processed */ ++#endif ++ + if (GamCheckEvent (event)) break; /* event has been processed */ + if (BrowseCheckEvent (event, &retval, &done)) break; /* event eaten */ + if (TextCheckEvent (event, &retval, &done)) break; /* event eaten */ +@@ -344,6 +422,9 @@ + + if (BrowseDelWin(client_event->window)) break; + if (TextDelWin(client_event->window)) break; ++#ifdef TV_MULTILINGUAL ++ if (CharsetDelWin(client_event->window)) break; ++#endif + + if (client_event->window == infoW) InfoBox(0); + else if (client_event->window == gamW) GamBox(0); +@@ -359,6 +440,24 @@ + else if (client_event->window == tiffW) TIFFDialog(0); + #endif + ++#ifdef HAVE_PNG ++ else if (client_event->window == pngW) PNGDialog(0); ++#endif ++ ++ else if (client_event->window == pcdW) PCDDialog(0); ++ ++#ifdef HAVE_PIC2 ++ else if (client_event->window == pic2W) PIC2Dialog(0); ++#endif ++ ++#ifdef HAVE_PCD ++ else if (client_event->window == pcdW) PCDDialog(0); ++#endif ++ ++#ifdef HAVE_MGCSFX ++ else if (client_event->window == mgcsfxW) MGCSFXDialog(0); ++#endif ++ + else if (client_event->window == mainW) Quit(0); + } + } +@@ -534,10 +633,21 @@ + #ifdef HAVE_JPEG + if (wasJpegUp) { JPEGDialog(wasJpegUp); wasJpegUp=0; } + #endif +- + #ifdef HAVE_TIFF + if (wasTiffUp) { TIFFDialog(wasTiffUp); wasTiffUp=0; } + #endif ++#ifdef HAVE_PNG ++ if (wasPngUp) { PNGDialog(wasJpegUp); wasPngUp=0; } ++#endif ++#ifdef HAVE_PCD ++ if (wasPcdUp) { PCDDialog(wasPcdUp); wasPcdUp=0; } ++#endif ++#ifdef HAVE_PIC2 ++ if (wasPic2Up) { PIC2Dialog(wasPic2Up); wasPic2Up=0; } ++#endif ++#ifdef HAVE_MGCSFX ++ if (wasMgcSfxUp) { MGCSFXDialog(wasMgcSfxUp); wasMgcSfxUp=0; } ++#endif + } + } + } +@@ -572,10 +682,21 @@ + #ifdef HAVE_JPEG + if (jpegUp) { wasJpegUp = jpegUp; JPEGDialog(0); } + #endif +- + #ifdef HAVE_TIFF + if (tiffUp) { wasTiffUp = tiffUp; TIFFDialog(0); } + #endif ++#ifdef HAVE_PNG ++ if (pngUp) { wasPngUp = pngUp; PNGDialog(0); } ++#endif ++#ifdef HAVE_PCD ++ if (pcdUp) { wasPcdUp = pcdUp; PCDDialog(0); } ++#endif ++#ifdef HAVE_PIC2 ++ if (pic2Up) { wasPic2Up = pic2Up; PIC2Dialog(0); } ++#endif ++#ifdef HAVE_MGCSFX ++ if (mgcsfxUp) { wasMgcSfxUp = mgcsfxUp; MGCSFXDialog(0); } ++#endif + } + } + } +@@ -641,6 +762,30 @@ + p_offy = xwa.y; + } + ++ /* Gather info to keep right border inside */ ++ { ++ Window current; ++ Window root_r; ++ Window parent_r; ++ Window *children_r; ++ int nchildren_r; ++ XWindowAttributes xwa; ++ ++ parent_r=mainW; ++ current=mainW; ++ do { ++ current=parent_r; ++ XQueryTree(theDisp, current, &root_r, &parent_r, ++ &children_r, &nchildren_r); ++ if (children_r!=NULL) { ++ XFree(children_r); ++ } ++ } while(parent_r!=root_r); ++ XGetWindowAttributes(theDisp, current, &xwa); ++ debkludge_offx=eWIDE-xwa.width+p_offx; ++ debkludge_offy=eHIGH-xwa.height+p_offy; ++ } ++ + + /* move window around a bit... */ + { +@@ -997,7 +1142,8 @@ + + int i; + char txt[512], str[PRINTCMDLEN + 10]; +- static char *labels[] = { " Color", " Grayscale", " B/W", "\033Cancel" }; ++ static char *labels[] = { "\03Color", "\07Grayscale", " B/W", "\033Cancel" }; ++ /* ^B ("\02") already used for moving cursor back */ + + strcpy(txt, "Print: Enter a command that will read a PostScript file "); + strcat(txt, "from stdin and print it to the desired printer.\n\n"); +@@ -1147,6 +1293,26 @@ + if (TIFFCheckEvent(event)) break; + #endif + ++#ifdef HAVE_PNG ++ if (PNGCheckEvent (event)) break; ++#endif ++ ++#ifdef HAVE_PCD ++ if (PCDCheckEvent (event)) break; /* event has been processed */ ++#endif ++ ++#ifdef HAVE_PIC2 ++ if (PIC2CheckEvent(event)) break; ++#endif ++ ++#ifdef HAVE_MGCSFX ++ if (MGCSFXCheckEvent(event)) break; ++#endif ++ ++#ifdef TV_MULTILINGUAL ++ if (CharsetCheckEvent(event)) break; ++#endif ++ + if (GamCheckEvent (event)) break; + if (BrowseCheckEvent (event, &retval, &done)) break; + if (TextCheckEvent (event, &retval, &done)) break; +@@ -1276,6 +1442,48 @@ + else if (shift) BlurPaint(); + break; + ++ case Button4: /* note min vs. max, + vs. - */ ++ if (win == ctrlW || win == nList.win || win == nList.scrl.win) { ++ SCRL *sp=&nList.scrl; ++ int halfpage=sp->page/2; ++ ++ if (sp->val > sp->min+halfpage) ++ SCSetVal(sp,sp->val-halfpage); ++ else ++ SCSetVal(sp,sp->min); ++ } ++ else if (win == dirW || win == dList.win || win == dList.scrl.win) { ++ SCRL *sp=&dList.scrl; ++ int halfpage=sp->page/2; ++ ++ if (sp->val > sp->min+halfpage) ++ SCSetVal(sp,sp->val-halfpage); ++ else ++ SCSetVal(sp,sp->min); ++ } ++ break; ++ ++ case Button5: /* note max vs. min, - vs. + */ ++ if (win == ctrlW || win == nList.win || win == nList.scrl.win) { ++ SCRL *sp=&nList.scrl; ++ int halfpage=sp->page/2; ++ ++ if (sp->val < sp->max-halfpage) ++ SCSetVal(sp,sp->val+halfpage); ++ else ++ SCSetVal(sp,sp->max); ++ } ++ else if (win == dirW || win == dList.win || win == dList.scrl.win) { ++ SCRL *sp=&dList.scrl; ++ int halfpage=sp->page/2; ++ ++ if (sp->val < sp->max-halfpage) ++ SCSetVal(sp,sp->val+halfpage); ++ else ++ SCSetVal(sp,sp->max); ++ } ++ break; ++ + default: break; + } + } +@@ -1364,16 +1572,35 @@ + if (TIFFCheckEvent(event)) break; + #endif + ++#ifdef HAVE_PNG ++ if (PNGCheckEvent (event)) break; ++#endif ++ ++ if (PCDCheckEvent (event)) break; ++ ++#ifdef HAVE_PIC2 ++ if (PIC2CheckEvent(event)) break; ++#endif ++ ++#ifdef HAVE_PCD ++ if (PCDCheckEvent (event)) break; ++#endif ++ ++#ifdef HAVE_MGCSFX ++ if (MGCSFXCheckEvent(event)) break; ++#endif ++ + if (GamCheckEvent (event)) break; + if (BrowseCheckEvent (event, &retval, &done)) break; + if (TextCheckEvent (event, &retval, &done)) break; + + +- /* check for pageup/pagedown, 'p' in main window +- (you can use shift-up or shift-down if no crop rectangle drawn) +- (for viewing multipage docs) */ ++ /* Support for multi-image files ("multipage docs"). Check for PgUp/PgDn ++ or 'p' in any window but control or directory; PgUp/PgDn are already ++ used to page through the file list in those windows. If no cropping ++ rectangle is active, shift-Up and shift-Down also work. */ + +- if (key_event->window == mainW) { ++ if (key_event->window != ctrlW && key_event->window != dirW) { + dealt = 1; + + ck = CursorKey(ks, shift, 0); +@@ -1578,13 +1805,13 @@ + } + break; + +- case '\010': +- case '\177': FakeButtonPress(&but[BPREV]); break; ++ case '\010': FakeButtonPress(&but[BPREV]); break; + + + case '\014': FakeButtonPress(&but[BLOAD]); break; /* ^L */ + case '\023': FakeButtonPress(&but[BSAVE]); break; /* ^S */ + case '\020': FakeButtonPress(&but[BPRINT]); break; /* ^P */ ++ case '\177': + case '\004': FakeButtonPress(&but[BDELETE]); break; /* ^D */ + + /* BCOPY, BCUT, BPASTE, BCLEAR handled in 'meta' case */ +@@ -2025,6 +2252,16 @@ + if (xwa->width < dispWIDE && xwc.x < p_offx) xwc.x = p_offx; + if (xwa->height < dispHIGH && xwc.y < p_offy) xwc.y = p_offy; + ++ /* Try to keep bottom right decorations inside */ ++ if (xwc.x+eWIDE-debkludge_offx>dispWIDE) { ++ xwc.x=dispWIDE-eWIDE+debkludge_offx; ++ if (xwc.x<0) xwc.x=0; ++ } ++ if (xwc.y+eHIGH-debkludge_offy>dispHIGH) { ++ xwc.y=dispHIGH-eHIGH+debkludge_offy; ++ if (xwc.y<0) xwc.y=0; ++ } ++ + xwc.width = xwa->width; + xwc.height = xwa->height; + +@@ -2370,6 +2607,24 @@ + if (tiffUp) TIFFDialog(0); /* close tiff window */ + #endif + ++#ifdef HAVE_PNG ++ if (pngUp) PNGDialog(0); /* close png window */ ++#endif ++ ++ if (pcdUp) PCDDialog(0); /* close pcd window */ ++ ++#ifdef HAVE_PIC2 ++ if (pic2Up) PIC2Dialog(0); /* close pic2 window */ ++#endif ++ ++#ifdef HAVE_PCD ++ if (pcdUp) PCDDialog(0); /* close pcd window */ ++#endif ++ ++#ifdef HAVE_MGCSFX ++ if (mgcsfxUp) MGCSFXDialog(0); /* close mgcsfx window */ ++#endif ++ + ClosePopUp(); + + /* make the interrupt signal look like a '\n' keypress in ctrlW */ +@@ -2574,26 +2829,43 @@ + static void paintLine(x,y,x1,y1) + int x,y,x1,y1; + { +- int dx,dy,i,lx,ly,adx,ady; ++ int t,dx,dy,d,dd; + +- dx = x1-x; dy = y1-y; +- adx = abs(dx); ady = abs(dy); ++ dx = abs(x1-x); dy = abs(y1-y); + +- if (dx == 0 && dy == 0) paintPixel(x,y); +- +- else if (adx > ady) { /* X is major axis */ +- for (i=0; i<=adx; i++) { +- lx = x + (i * dx + (adx/2)) / abs(dx); +- ly = y + (i * dy + (adx/2)) / abs(dx); +- paintPixel(lx,ly); ++ if (dx >= dy) { /* X is major axis */ ++ if (x > x1) { ++ t = x; x = x1; x1 = t; ++ t = y; y = y1; y1 = t; ++ } ++ d = dy + dy - dx; ++ dd = y < y1 ? 1 : -1; ++ while (x <= x1) { ++ paintPixel(x,y); ++ if (d > 0) { ++ y += dd; ++ d -= dx + dx; ++ } ++ ++x; ++ d += dy + dy; + } + } + + else { /* Y is major axis */ +- for (i=0; i<=ady; i++) { +- lx = x + (i * dx + (ady/2)) / ady; +- ly = y + (i * dy + (ady/2)) / ady; +- paintPixel(lx,ly); ++ if (y > y1) { ++ t = x; x = x1; x1 = t; ++ t = y; y = y1; y1 = t; ++ } ++ d = dx + dx - dy; ++ dd = x < x1 ? 1 : -1; ++ while (y <= y1) { ++ paintPixel(x,y); ++ if (d > 0) { ++ x += dd; ++ d -= dy + dy; ++ } ++ ++y; ++ d += dx + dx; + } + } + +diff -ruN xv-3.10a-bugfixes/xvfits.c xv-3.10a-enhancements/xvfits.c +--- xv-3.10a-bugfixes/xvfits.c 2005-04-02 21:08:45.000000000 -0800 ++++ xv-3.10a-enhancements/xvfits.c 2005-04-17 14:45:28.000000000 -0700 +@@ -14,7 +14,7 @@ + * provided "as is" without express or implied warranty. + */ + +- ++#define NEEDSDIR /* for S_IRUSR|S_IWUSR */ + #include "xv.h" + + #define NCARDS (36) +@@ -228,7 +228,7 @@ + * If there was a problem writing files, then a error message will be set. + */ + +- int i, npixels=nx * ny, nwrt; ++ int i, npixels=nx * ny, nwrt, tmpfd; + FILE *fp; + char *error; + char filename[70]; +@@ -254,7 +254,12 @@ + + for (i=0; i < nz && !error; i++) { + sprintf(filename, "%s%d", basename, i+1); +- fp = xv_fopen(filename, "w"); ++ tmpfd = open(filename,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR); ++ if (tmpfd < 0) { ++ error = "Unable to open temporary file"; ++ break; ++ } ++ fp = fdopen(tmpfd, "w"); + if (!fp) { + error = "Unable to open temporary file"; + break; +@@ -262,13 +267,17 @@ + + if (wrheader(fp, nx, ny, comment)) { + error = "I/O error writing temporary file"; ++ fflush(fp); + fclose(fp); + unlink(filename); ++ close(tmpfd); + break; + } + + nwrt = fwrite(image+i*npixels, sizeof(byte), (size_t) npixels, fp); ++ fflush(fp); + fclose(fp); ++ close(tmpfd); + + if (nwrt == 0) { /* failed to write any data */ + error = "I/O error writing temporary file"; +diff -ruN xv-3.10a-bugfixes/xvgam.c xv-3.10a-enhancements/xvgam.c +--- xv-3.10a-bugfixes/xvgam.c 2004-05-16 18:02:11.000000000 -0700 ++++ xv-3.10a-enhancements/xvgam.c 2004-05-16 18:06:48.000000000 -0700 +@@ -265,11 +265,11 @@ + BTCreate(&gbut[G_BRNDCOL], cmapF, 5 + 66 + 67 + 2, 189, 66, BUTTH, + "Random", infofg, infobg, hicol, locol); + +- DCreate(&rhDial, cmapF, 5, 215, 66, 100, 0,360,180, 5, ++ DCreate(&rhDial, cmapF, 5, 215, 66, 100, 0.0, 360.0, 180.0, 1.0, 5.0, + infofg, infobg, hicol, locol, "Hue", NULL); +- DCreate(&gsDial, cmapF, 72, 215, 66, 100, 0,360,180, 5, ++ DCreate(&gsDial, cmapF, 72, 215, 66, 100, 0.0, 360.0, 180.0, 1.0, 5.0, + infofg, infobg, hicol, locol, "Sat.", NULL); +- DCreate(&bvDial, cmapF, 139, 215, 66, 100, 0,360,180, 5, ++ DCreate(&bvDial, cmapF, 139, 215, 66, 100, 0.0, 360.0, 180.0, 1.0, 5.0, + infofg, infobg, hicol, locol, "Value", NULL); + + rhDial.drawobj = gsDial.drawobj = bvDial.drawobj = dragEditColor; +@@ -359,7 +359,7 @@ + + srcHD.drawobj = dstHD.drawobj = whtHD.drawobj = dragHueDial; + +- DCreate(&satDial, hsvF, 100, 199, 100, 121, -100, 100, 0, 5, ++ DCreate(&satDial, hsvF, 100, 199, 100, 121, -100.0, 100.0, 0.0, 1.0, 5.0, + infofg, infobg,hicol,locol, "Saturation", "%"); + + hueRB = RBCreate(NULL, hsvF, 7, 153, "1", +@@ -722,7 +722,7 @@ + + if (whtHD.enabCB.val && whtHD.satval) hsvnonlinear++; + +- if (satDial.val != 0) hsvnonlinear++; ++ if (satDial.val != 0.0) hsvnonlinear++; + + /* check intensity graf */ + for (i=0; i<256 && intGraf.func[i]==i; i++); +@@ -1291,14 +1291,14 @@ + rgb2hsv(rcmap[editColor], gcmap[editColor], bcmap[editColor], &h, &s, &v); + if (h<0) h = 0; + +- DSetVal(&rhDial, (int) h); +- DSetVal(&gsDial, (int) (s*100)); +- DSetVal(&bvDial, (int) (v*100)); ++ DSetVal(&rhDial, h); ++ DSetVal(&gsDial, s*100); ++ DSetVal(&bvDial, v*100); + } + else { +- DSetVal(&rhDial, rcmap[editColor]); +- DSetVal(&gsDial, gcmap[editColor]); +- DSetVal(&bvDial, bcmap[editColor]); ++ DSetVal(&rhDial, (double)rcmap[editColor]); ++ DSetVal(&gsDial, (double)gcmap[editColor]); ++ DSetVal(&bvDial, (double)bcmap[editColor]); + } + } + +@@ -1310,16 +1310,15 @@ + + if (hsvmode) { + int rv, gv, bv; +- hsv2rgb((double) rhDial.val, ((double) gsDial.val) / 100.0, +- ((double) bvDial.val) / 100.0, &rv, &gv, &bv); ++ hsv2rgb(rhDial.val, gsDial.val / 100.0, bvDial.val / 100.0, &rv, &gv, &bv); + rcmap[editColor] = rv; + gcmap[editColor] = gv; + bcmap[editColor] = bv; + } + else { +- rcmap[editColor] = rhDial.val; +- gcmap[editColor] = gsDial.val; +- bcmap[editColor] = bvDial.val; ++ rcmap[editColor] = (int)rhDial.val; ++ gcmap[editColor] = (int)gsDial.val; ++ bcmap[editColor] = (int)bvDial.val; + } + } + +@@ -1561,9 +1560,9 @@ + gsDial.title = "Green"; + bvDial.title = "Blue"; + +- DSetRange(&rhDial, 0, 255, rcmap[editColor], 16); +- DSetRange(&gsDial, 0, 255, gcmap[editColor], 16); +- DSetRange(&bvDial, 0, 255, bcmap[editColor], 16); ++ DSetRange(&rhDial, 0.0, 255.0, (double)rcmap[editColor], 1.0, 16.0); ++ DSetRange(&gsDial, 0.0, 255.0, (double)gcmap[editColor], 1.0, 16.0); ++ DSetRange(&bvDial, 0.0, 255.0, (double)bcmap[editColor], 1.0, 16.0); + + XClearWindow(theDisp, rhDial.win); DRedraw(&rhDial); + XClearWindow(theDisp, gsDial.win); DRedraw(&gsDial); +@@ -1581,9 +1580,9 @@ + &h, &s, &v); + + if (h<0.0) h = 0.0; +- DSetRange(&rhDial, 0, 360, (int) h, 5); +- DSetRange(&gsDial, 0, 100, (int) (s*100), 5); +- DSetRange(&bvDial, 0, 100, (int) (v*100), 5); ++ DSetRange(&rhDial, 0.0, 360.0, h, 1.0, 5.0); ++ DSetRange(&gsDial, 0.0, 100.0, s*100, 1.0, 5.0); ++ DSetRange(&bvDial, 0.0, 100.0, v*100, 1.0, 5.0); + + XClearWindow(theDisp, rhDial.win); DRedraw(&rhDial); + XClearWindow(theDisp, gsDial.win); DRedraw(&gsDial); +@@ -1891,7 +1890,7 @@ + } + + /* apply satDial value to s */ +- s = s + ((double) satDial.val) / 100.0; ++ s = s + satDial.val / 100.0; + if (s<0.0) s = 0.0; + if (s>1.0) s = 1.0; + +@@ -2007,7 +2006,7 @@ + + gs->hueRBnum = RBWhich(hueRB); + +- gs->satval = satDial.val; ++ gs->satval = (int)satDial.val; + GetGrafState(&intGraf,&gs->istate); + GetGrafState(&rGraf, &gs->rstate); + GetGrafState(&gGraf, &gs->gstate); +@@ -2064,8 +2063,8 @@ + changed++; + } + +- if (gs->satval != satDial.val) { +- DSetVal(&satDial,gs->satval); ++ if (gs->satval != (int)satDial.val) { ++ DSetVal(&satDial,(double)gs->satval); + changed++; + } + +@@ -3200,7 +3199,7 @@ + + if (whtHD.enabCB.val && whtHD.satval) hsvmod++; + +- if (satDial.val != 0) hsvmod++; ++ if (satDial.val != 0.0) hsvmod++; + + /* check intensity graf */ + for (i=0; i<256; i++) { +@@ -3284,7 +3283,7 @@ + } + + /* apply satDial value to s */ +- s = s + satDial.val; ++ s = s + (int)satDial.val; + if (s< 0) s = 0; + if (s>100) s = 100; + +diff -ruN xv-3.10a-bugfixes/xvgif.c xv-3.10a-enhancements/xvgif.c +--- xv-3.10a-bugfixes/xvgif.c 2005-04-03 11:53:13.000000000 -0700 ++++ xv-3.10a-enhancements/xvgif.c 2005-04-30 21:47:44.000000000 -0700 +@@ -50,6 +50,7 @@ + BytesPerScanline, /* bytes per scanline in output raster */ + ColorMapSize, /* number of colors */ + Background, /* background color */ ++ Transparent, /* transparent color (GRR 19980314) */ + CodeSize, /* Code size, read from GIF header */ + InitCodeSize, /* Starting code size, used during Clear */ + Code, /* Value returned by ReadCode */ +@@ -111,16 +112,20 @@ + + register byte ch, *origptr; + register int i, block; +- int aspect, gotimage; ++ int aspect; ++ char tmpname[256]; ++ byte r[256], g[256], b[256]; + + /* initialize variables */ +- BitOffset = XC = YC = OutCount = gotimage = 0; ++ BitOffset = XC = YC = OutCount = 0; + Pass = -1; + RawGIF = Raster = pic8 = NULL; + gif89 = 0; ++ Transparent = -1; + + pinfo->pic = (byte *) NULL; + pinfo->comment = (char *) NULL; ++ pinfo->numpages= 0; + + bname = BaseName(fname); + fp = xv_fopen(fname,"r"); +@@ -145,7 +150,7 @@ + + if (fread(dataptr, (size_t) filesize, (size_t) 1, fp) != 1) + return( gifError(pinfo, "GIF data read failed") ); +- ++ fclose(fp); + + origptr = dataptr; + +@@ -161,6 +166,7 @@ + RWidth = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */ + ch = NEXTBYTE; + RHeight = ch + 0x100 * NEXTBYTE; ++ if (DEBUG) fprintf(stderr,"GIF89 logical screen = %d x %d\n",RWidth,RHeight); + + ch = NEXTBYTE; + HasColormap = ((ch & COLORMAPMASK) ? True : False); +@@ -176,6 +182,8 @@ + if (!gif89) return(gifError(pinfo,"corrupt GIF file (screen descriptor)")); + else normaspect = (float) (aspect + 15) / 64.0; /* gif89 aspect ratio */ + if (DEBUG) fprintf(stderr,"GIF89 aspect = %f\n", normaspect); ++ /* FIXME: apparently this _should_ apply to all frames in a multi-image ++ * GIF (i.e., PgUp/PgDn), but it doesn't */ + } + + +@@ -183,20 +191,23 @@ + + if (HasColormap) + for (i=0; i<ColorMapSize; i++) { +- pinfo->r[i] = NEXTBYTE; +- pinfo->g[i] = NEXTBYTE; +- pinfo->b[i] = NEXTBYTE; ++ r[i] = NEXTBYTE; ++ g[i] = NEXTBYTE; ++ b[i] = NEXTBYTE; + } + else { /* no colormap in GIF file */ + /* put std EGA palette (repeated 16 times) into colormap, for lack of + anything better to do */ + + for (i=0; i<256; i++) { +- pinfo->r[i] = EGApalette[i&15][0]; +- pinfo->g[i] = EGApalette[i&15][1]; +- pinfo->b[i] = EGApalette[i&15][2]; ++ r[i] = EGApalette[i&15][0]; ++ g[i] = EGApalette[i&15][1]; ++ b[i] = EGApalette[i&15][2]; + } + } ++ memcpy(pinfo->r, r, sizeof r); ++ memcpy(pinfo->g, g, sizeof g); ++ memcpy(pinfo->b, b, sizeof b); + + /* possible things at this point are: + * an application extension block +@@ -334,12 +345,28 @@ + if (DEBUG) fprintf(stderr,"Graphic Control extension\n\n"); + + SetISTR(ISTR_INFO, "%s: %s", bname, +- "Graphic Control Extension in GIF file. Ignored."); ++ "Graphic Control Extension ignored."); + +- /* read (and ignore) data sub-blocks */ ++ /* read (and ignore) data sub-blocks, unless compositing with ++ * user-defined background */ + do { +- j = 0; sbsize = NEXTBYTE; +- while (j<sbsize) { SKIPBYTE; j++; } ++ j = 0; ++ sbsize = NEXTBYTE; ++ /* GRR 19980314: get transparent index out of block */ ++ if (have_imagebg && sbsize == 4 && Transparent < 0) { ++ byte packed_fields = NEXTBYTE; ++ ++ j++; ++ SKIPBYTE; j++; ++ SKIPBYTE; j++; ++ if (packed_fields & 1) { ++ Transparent = NEXTBYTE; ++ j++; ++ } ++ } ++ while (j<sbsize) { ++ SKIPBYTE; j++; ++ } + } while (sbsize); + } + +@@ -376,36 +403,42 @@ + + + else if (block == IMAGESEP) { +- if (DEBUG) fprintf(stderr,"imagesep (got=%d) ",gotimage); ++ if (DEBUG) fprintf(stderr,"imagesep (page=%d) ",pinfo->numpages+1); + if (DEBUG) fprintf(stderr," at start: offset=0x%x\n",dataptr-RawGIF); + +- if (gotimage) { /* just skip over remaining images */ +- int i,misc,ch,ch1; ++ BitOffset = XC = YC = Pass = OutCount = 0; + +- /* skip image header */ +- SKIPBYTE; SKIPBYTE; /* left position */ +- SKIPBYTE; SKIPBYTE; /* top position */ +- SKIPBYTE; SKIPBYTE; /* width */ +- SKIPBYTE; SKIPBYTE; /* height */ +- misc = NEXTBYTE; /* misc. bits */ +- +- if (misc & 0x80) { /* image has local colormap. skip it */ +- for (i=0; i< 1 << ((misc&7)+1); i++) { +- SKIPBYTE; SKIPBYTE; SKIPBYTE; ++ if (pinfo->numpages > 0) { /* do multipage stuff */ ++ if (pinfo->numpages == 1) { /* first time only... */ ++ xv_mktemp(pinfo->pagebname, "xvpgXXXXXX"); ++ if (pinfo->pagebname[0] == '\0') { ++ ErrPopUp("LoadGIF: Unable to create temporary filename???", ++ "\nHow unlikely!"); ++ return 0; + } + } +- +- SKIPBYTE; /* minimum code size */ +- +- /* skip image data sub-blocks */ +- do { +- ch = ch1 = NEXTBYTE; +- while (ch--) SKIPBYTE; +- if ((dataptr - RawGIF) > filesize) break; /* EOF */ +- } while(ch1); ++ sprintf(tmpname, "%s%d", pinfo->pagebname, pinfo->numpages); ++ fp = xv_fopen(tmpname, "w"); ++ if (!fp) { ++ ErrPopUp("LoadGIF: Unable to open temp file", "\nDang!"); ++ return 0; ++ } ++ if (WriteGIF(fp, pinfo->pic, pinfo->type, pinfo->w, pinfo->h, pinfo->r, ++ pinfo->g, pinfo->b, numcols, pinfo->colType, NULL)) { ++ fclose(fp); ++ ErrPopUp("LoadGIF: Error writing temp file", "\nBummer!"); ++ return 0; ++ } ++ fclose(fp); ++ free(pinfo->pic); ++ pinfo->pic = (byte *) NULL; ++ if (HasColormap) { ++ memcpy(pinfo->r, r, sizeof r); ++ memcpy(pinfo->g, g, sizeof g); ++ memcpy(pinfo->b, b, sizeof b); ++ } + } +- +- else if (readImage(pinfo)) gotimage = 1; ++ if (readImage(pinfo)) pinfo->numpages++; + if (DEBUG) fprintf(stderr," at end: dataptr=0x%x\n",dataptr-RawGIF); + } + +@@ -425,7 +458,7 @@ + sprintf(str, "Unknown block type (0x%02x) at offset 0x%x", + block, (dataptr - origptr) - 1); + +- if (!gotimage) return gifError(pinfo, str); ++ if (!pinfo->numpages) return gifError(pinfo, str); + else gifWarning(str); + } + +@@ -438,8 +471,34 @@ + free(RawGIF); RawGIF = NULL; + free(Raster); Raster = NULL; + +- if (!gotimage) ++ if (!pinfo->numpages) + return( gifError(pinfo, "no image data found in GIF file") ); ++ if (pinfo->numpages > 1) { ++ /* write the last page temp file */ ++ int numpages = pinfo->numpages; ++ char *comment = pinfo->comment; ++ sprintf(tmpname, "%s%d", pinfo->pagebname, pinfo->numpages); ++ fp = xv_fopen(tmpname, "w"); ++ if (!fp) { ++ ErrPopUp("LoadGIF: Unable to open temp file", "\nDang!"); ++ return 0; ++ } ++ if (WriteGIF(fp, pinfo->pic, pinfo->type, pinfo->w, pinfo->h, pinfo->r, ++ pinfo->g, pinfo->b, numcols, pinfo->colType, NULL)) { ++ fclose(fp); ++ ErrPopUp("LoadGIF: Error writing temp file", "\nBummer!"); ++ return 0; ++ } ++ fclose(fp); ++ free(pinfo->pic); ++ pinfo->pic = (byte *) NULL; ++ ++ /* load the first page temp file */ ++ sprintf(tmpname, "%s%d", pinfo->pagebname, 1); ++ i = LoadGIF(tmpname, pinfo); ++ pinfo->numpages = numpages; ++ pinfo->comment = comment; ++ } + + return 1; + } +@@ -484,6 +543,17 @@ + } + + ++ /* GRR 19980314 */ ++ /* need not worry about size of EGA palette: full 256 colors */ ++ if (have_imagebg && Transparent >= 0 && ++ Transparent < ((Misc&0x80)? (1 << ((Misc&7)+1)) : ColorMapSize) ) ++ { ++ pinfo->r[Transparent] = (imagebgR >> 8); ++ pinfo->g[Transparent] = (imagebgG >> 8); ++ pinfo->b[Transparent] = (imagebgB >> 8); ++ } ++ ++ + + /* Start reading the raster data. First we get the intial code size + * and compute decompressor constant values, based on this code size. +@@ -540,7 +610,7 @@ + return( gifError(pinfo, "image dimensions out of range") ); + picptr = pic8 = (byte *) malloc((size_t) maxpixels); + if (!pic8) FatalError("LoadGIF: couldn't malloc 'pic8'"); +- ++ + + + /* Decompress the file, continuing until you see the GIF EOF code. +@@ -642,11 +712,10 @@ + SetISTR(ISTR_WARNING,"%s: %s", bname, + "This GIF file seems to be truncated. Winging it."); + if (!Interlace) /* clear->EOBuffer */ +- xvbzero((char *) pic8+npixels, (size_t) (maxpixels-npixels)); ++ xvbzero((char *) pic8+npixels, ++ (size_t) (maxpixels-npixels<0 ? 0 : maxpixels-npixels)); + } + +- fclose(fp); +- + /* fill in the PICINFO structure */ + + pinfo->pic = pic8; +diff -ruN xv-3.10a-bugfixes/xvgrab.c xv-3.10a-enhancements/xvgrab.c +--- xv-3.10a-bugfixes/xvgrab.c 2004-05-16 18:03:30.000000000 -0700 ++++ xv-3.10a-enhancements/xvgrab.c 2005-04-25 23:39:32.000000000 -0700 +@@ -14,6 +14,13 @@ + #define NEEDSTIME + #include "xv.h" + ++/* Allow flexibility in use of buttons JPD */ ++#define WINDOWGRABMASK Button1Mask /* JPD prefers Button2Mask */ ++#define RECTGTRACKMASK Button2Mask /* JPD prefers Button1Mask*/ ++#define CANCELGRABMASK Button3Mask ++ ++#define DO_GRABFLASH /* JPD prefers not to do that; just a loss of time ... */ ++ + + union swapun { + CARD32 l; +@@ -69,12 +76,15 @@ + 0 if cancelled */ + + int i, x, y, x1, y1, x2, y2, ix, iy, iw, ih, rv; +- int rx, ry, pretendGotB1, autograb; ++ int rx, ry, GotButton, autograb; ++ int cancelled = 0; + Window rW, cW, clickWin; + unsigned int mask; ++#ifdef RECOLOR_GRAB_CURSOR + XColor fc, bc; ++#endif + +- pretendGotB1 = 0; ++ GotButton = 0; + + if (grabInProgress) return 0; /* avoid recursive grabs during delay */ + +@@ -122,15 +132,23 @@ + free(grabPic); grabPic = (byte *) NULL; + } + +- ++ /* recolor cursor to indicate that grabbing is active? */ ++ /* Instead, change cursor JPD */ ++#ifdef RECOLOR_GRAB_CURSOR + fc.flags = bc.flags = DoRed | DoGreen | DoBlue; + fc.red = fc.green = fc.blue = 0xffff; + bc.red = bc.green = bc.blue = 0x0000; + XRecolorCursor(theDisp, tcross, &fc, &bc); ++#endif + + + XBell(theDisp, 0); /* beep once at start of grab */ + ++ /* Change cursor to top_left_corner JPD */ ++ XGrabPointer(theDisp, rootW, False, ++ PointerMotionMask|ButtonPressMask|ButtonReleaseMask, ++ GrabModeAsync, GrabModeAsync, None, tlcorner, CurrentTime); ++ + if (!autograb) XGrabButton(theDisp, (u_int) AnyButton, 0, rootW, False, 0, + GrabModeAsync, GrabModeSync, None, tcross); + +@@ -142,7 +160,7 @@ + rv = 0; + goto exit; + } +- else { pretendGotB1 = 1; mask = Button1Mask; } ++ else { GotButton = 1; mask = WINDOWGRABMASK; } + } + + else { /* !autograb */ +@@ -170,16 +188,20 @@ + } + } + ++ XUngrabPointer(theDisp, CurrentTime); ++ /* Reset cursor to XC_tcross JPD */ ++ XGrabPointer(theDisp, rootW, False, ++ PointerMotionMask|ButtonPressMask|ButtonReleaseMask, ++ GrabModeAsync, GrabModeAsync, None, tcross, CurrentTime); + + /*** + *** got button click (or pretending we did, if autograb) + ***/ + +- +- if (mask & Button3Mask || rW!=rootW) { /* Button3: CANCEL GRAB */ ++ if (mask & CANCELGRABMASK || rW!=rootW) { /* CANCEL GRAB */ + while (1) { /* wait for button to be released */ + if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x1,&y1,&mask)) { +- if (!(mask & Button3Mask)) break; ++ if (!(mask & CANCELGRABMASK)) break; + } + } + +@@ -187,19 +209,21 @@ + XBell(theDisp, 0); + XBell(theDisp, 0); + rv = 0; ++ cancelled = 1; + goto exit; + } + + +- +- if (mask & Button1Mask) { /* Button1: GRAB WINDOW (& FRAME, maybe) */ +- while (!pretendGotB1) { /* wait for button to be released, if clicked */ ++ if (mask & WINDOWGRABMASK) { /* GRAB WINDOW (& FRAME, maybe) */ ++ while (!GotButton) { /* wait for button to be released, if clicked */ + int rx,ry,x1,y1; Window rW, cW; + if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x1,&y1,&mask)) { +- if (!(mask & Button1Mask)) break; ++ if (!(mask & WINDOWGRABMASK)) break; + } + } + ++ grabwin: ++ + clickWin = (cW) ? cW : rootW; + + if (clickWin == rootW) { /* grab entire screen */ +@@ -223,7 +247,6 @@ + } + } + +- + /* range checking: keep rectangle fully on-screen */ + if (ix<0) { iw += ix; ix = 0; } + if (iy<0) { ih += iy; iy = 0; } +@@ -244,8 +267,7 @@ + endflash(); + } + +- +- else { /* Button2: TRACK A RECTANGLE */ ++ else { /* TRACK A RECTANGLE */ + int origrx, origry; + + clickWin = rootW; +@@ -259,7 +281,7 @@ + /* Wait for button release while tracking rectangle on screen */ + while (1) { + if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x,&y,&mask)) { +- if (!(mask & Button2Mask)) break; ++ if (!(mask & RECTGTRACKMASK)) break; + } + + flashrect(ix, iy, iw, ih, 0); /* turn off rect */ +@@ -276,6 +298,7 @@ + + flashrect(ix, iy, iw, ih, 0); /* turn off rect */ + ++#ifdef DO_GRABFLASH + /* flash the rectangle a bit... */ + for (i=0; i<5; i++) { + flashrect(ix, iy, iw, ih, 1); +@@ -283,13 +306,26 @@ + flashrect(ix, iy, iw, ih, 0); + XFlush(theDisp); Timer(100); + } ++#endif ++ + endflash(); + ++ /* if rectangle has zero width or height, search for child window JPD */ ++ if (iw==0 && ih==0) { ++ int xr, yr; ++ Window childW = 0; ++ if (rW && cW) ++ XTranslateCoordinates(theDisp, rW, cW, rx, ry, &xr, &yr, &childW); ++ if (childW) ++ cW = childW; ++ goto grabwin; ++ } ++ + XUngrabServer(theDisp); + } + +- + /*** ++ *** now that clickWin,ix,iy,iw,ih are known, try to grab the bits : + *** grab screen area (ix,iy,iw,ih) + ***/ + +@@ -303,9 +339,16 @@ + + SetCursors(-1); + +- + exit: + ++ XUngrabPointer(theDisp, CurrentTime); ++ XUngrabServer(theDisp); ++ ++ if (startGrab) { ++ startGrab = 0; ++ if (cancelled) Quit(0); ++ } ++ + if (hidewins) { /* remap XV windows */ + autoclose += 2; /* force it on once */ + if (mainW && dispMode == RMB_WINDOW) { +@@ -1217,7 +1260,3 @@ + + return 1; + } +- +- +- +- +diff -ruN xv-3.10a-bugfixes/xvhips.c xv-3.10a-enhancements/xvhips.c +--- xv-3.10a-bugfixes/xvhips.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvhips.c 2005-04-30 23:49:14.000000000 -0700 +@@ -0,0 +1,406 @@ ++/* ++ * xvhips.c - load routine for 'HIPS' format pictures ++ * ++ * LoadHIPS(fname, numcols) ++ */ ++ ++/* ++ * Copyright 1989, 1990 by the University of Pennsylvania ++ * ++ * Permission to use, copy, and distribute for non-commercial purposes, ++ * is hereby granted without fee, providing that the above copyright ++ * notice appear in all copies and that both the copyright notice and this ++ * permission notice appear in supporting documentation. ++ * ++ * The software may be modified for your own purposes, but modified versions ++ * may not be distributed. ++ * ++ * This software is provided "as is" without any express or implied warranty. ++ */ ++ ++#include "xv.h" ++ ++#ifdef HAVE_HIPS ++ ++#define Boolean FREDDIE ++#include "xvhips.h" ++#undef Boolean ++ ++#include <alloca.h> ++ ++#define LINES 100 ++#define LINELENGTH 132 ++ ++static int fread_header(int fd, struct header *hd); ++static char *getline(int fd, char **s, int *l); ++static int dfscanf(int fd); ++static void make_grayscale(char *r, char *g, char *b); ++static float hls_value (float n1, float n2, float hue); ++static void hls_to_rgb(float h, float l, float s, ++ float *r, float *g, float *b); ++static void make_huescale(char *r, char *g, char *b); ++static void make_heatscale(char *r, char *g, char *b); ++static int load_colourmap(char *filestem, int max_colours, ++ char *r, char *g, char *b); ++ ++/************************************************************************ ++ * ++ * Read Header routines ++ * ++ ************************************************************************/ ++ ++static char *ssave[LINES]; ++static int slmax[LINES]; ++static int lalloc = 0; ++//extern char *calloc(); ++ ++ ++ ++static int fread_header(fd, hd) ++ int fd; ++ struct header *hd; ++{ ++ int lineno, len, i; ++ char *s; ++ ++/*fprintf(stderr,"fread_header: entered\n");*/ ++ if(lalloc<1) { ++ ssave[0] = calloc(LINELENGTH, sizeof (char)); ++ slmax[0] = LINELENGTH; ++ lalloc = 1; ++ } ++/*fprintf(stderr,"fread_header: ssave allocated\n");*/ ++ getline(fd,&ssave[0],&slmax[0]); ++ hd->orig_name = calloc(strlen(ssave[0])+1, sizeof (char)); ++ strcpy(hd->orig_name,ssave[0]); ++ getline(fd,&ssave[0],&slmax[0]); ++ hd->seq_name = calloc(strlen(ssave[0])+1, sizeof (char)); ++ strcpy(hd->seq_name,ssave[0]); ++ hd->num_frame = dfscanf(fd); ++ getline(fd,&ssave[0],&slmax[0]); ++ hd->orig_date = calloc(strlen(ssave[0])+1, sizeof (char)); ++ strcpy(hd->orig_date,ssave[0]); ++ hd->rows = dfscanf(fd); ++ hd->cols = dfscanf(fd); ++ hd->bits_per_pixel = dfscanf(fd); ++ hd->bit_packing = dfscanf(fd); ++ hd->pixel_format = dfscanf(fd); ++ lineno = 0; ++ len = 1; ++ getline(fd,&ssave[0],&slmax[0]); ++ s = ssave[0]; ++ while(*(s += strlen(s)-3) == '|') { ++ len += strlen(ssave[lineno]); ++ lineno++; ++ if (lineno >= LINES) ++ fprintf(stderr, "Too many lines in header history"); ++ if(lineno >= lalloc) { ++ ssave[lineno] = calloc(LINELENGTH, sizeof (char)); ++ slmax[lineno] = LINELENGTH; ++ lalloc++; ++ } ++ getline(fd,&ssave[lineno],&slmax[lineno]); ++ s = ssave[lineno]; ++ } ++ len += strlen(ssave[lineno]); ++ hd->seq_history = calloc(len, sizeof (char)); ++ hd->seq_history[0] = '\0'; ++ for (i=0;i<=lineno;i++) ++ strcat(hd->seq_history,ssave[i]); ++ lineno = 0; ++ len = 1; ++ while(strcmp(getline(fd,&ssave[lineno],&slmax[lineno]),".\n")) { ++ len += strlen(ssave[lineno]); ++ lineno++; ++ if (lineno >= LINES) ++ fprintf(stderr, "Too many lines in header desc."); ++ if(lineno >= lalloc) { ++ ssave[lineno] = calloc(LINELENGTH, sizeof (char)); ++ slmax[lineno] = LINELENGTH; ++ lalloc++; ++ } ++ } ++ hd->seq_desc = calloc(len, sizeof (char)); ++ *hd->seq_desc = '\0'; ++ for (i=0;i<lineno;i++) ++ strcat(hd->seq_desc,ssave[i]); ++/*fprintf(stderr,"fread_header: exiting\n");*/ ++ return 0; ++} ++ ++ ++ ++static char *getline(fd,s,l) ++ int fd; ++ char **s; ++ int *l; ++{ ++ int i,m; ++ char c,*s1,*s2; ++ ++ i = 0; ++ s1 = *s; ++ m = *l; ++ while(read(fd,&c,1) == 1 && c != '\n') { ++ if (m-- <= 2) { ++ s2 = calloc(LINELENGTH+*l,sizeof (char)); ++ strcpy(s2,*s); ++ *s = s2; ++ *l += LINELENGTH; ++ m = LINELENGTH; ++ s1 = s2 + strlen(s2); ++ } ++ *s1++ = c; ++ } ++ if (c == '\n') { ++ *s1++ = '\n'; ++ *s1 = '\0'; ++ return *s; ++ } ++ fprintf(stderr, "Unexpected EOF while reading header."); ++ return NULL; ++} ++ ++ ++ ++static int dfscanf(fd) ++ int fd; ++{ ++ int i; ++ ++ getline(fd,&ssave[0],&slmax[0]); ++ sscanf(ssave[0],"%d",&i); ++ return(i); ++} ++ ++ ++ ++/*******************************************/ ++int LoadHIPS(fname,pinfo) ++ char *fname; ++ PICINFO * pinfo; ++/*******************************************/ ++{ ++ FILE *fp; ++ struct header h; ++ char * pic; ++ ++ /* open the stream, if necesary */ ++ fp=fopen(fname,"r"); ++ if (!fp) return 0; ++ ++ if (!fread_header(fileno(fp), &h)) { ++ SetISTR(ISTR_WARNING,"Can't read HIPS header"); ++ return 0; ++ } ++ ++ pinfo->w = h.cols; ++ pinfo->h = h.rows; ++ pic = pinfo->pic = (byte *) malloc(h.rows * h.cols); // GRR POSSIBLE OVERFLOW / FIXME ++ if (!pic) FatalError("couldn't malloc HIPS file"); ++ ++ if (!fread(pic, 1, h.cols*h.rows, fp)) { ++ SetISTR(ISTR_WARNING,"Error reading HIPS data.\n"); ++ return 0; ++ } ++ fclose (fp); ++ ++ pinfo->frmType = F_SUNRAS; ++ pinfo->colType = F_FULLCOLOR; ++ sprintf(pinfo->fullInfo, "HIPS file (%d bytes)", h.cols*h.rows); ++ sprintf(pinfo->shrtInfo, "HIPS file."); ++ pinfo->comment = (char *) NULL; ++ ++ { ++ char cmapname[256]; ++ /* Check header for colormap spec */ ++ char * s = h.seq_desc - 1; ++ char * cmaptag = "+COLORMAP"; ++ int sl = strlen(cmaptag); ++ cmapname[0] = 0; ++ while (*++s) ++ if (*s == '+') ++ if (strncmp(s, cmaptag, sl) == 0) { ++ char * p = s + sl; ++ while (*p && (*p == ' ' || *p == '\n' || *p == '\t')) p++; ++ sscanf(p, "%s", cmapname); ++ SetISTR(ISTR_INFO, cmapname); ++ fprintf(stderr, "Colormap = [%s]\n", cmapname); ++ } ++ ++ if (strcmp(cmapname, "gray") == 0 || strcmp(cmapname, "grey") == 0) ++ make_grayscale(pinfo->r, pinfo->g, pinfo->b); ++ else if (strcmp(cmapname, "heat") == 0) ++ make_heatscale(pinfo->r, pinfo->g, pinfo->b); ++ else if (strcmp(cmapname, "hues") == 0) ++ make_huescale(pinfo->r, pinfo->g, pinfo->b); ++ else if (!cmapname[0] || !load_colourmap(cmapname, 256, pinfo->r, pinfo->g, pinfo->b)) ++ make_grayscale(pinfo->r, pinfo->g, pinfo->b); ++ sprintf(pinfo->fullInfo, "HIPS file (%d x %d), Colormap = [%s]", h.cols, h.rows, cmapname); ++ } ++ ++ return 1; ++} ++ ++ ++ ++static void make_grayscale(char * r, char * g, char * b) ++{ ++ int i; ++ /* default grayscale colors */ ++ r[0] = 40; g[0] = 150; b[0] = 100; /* "green4" background */ ++ for(i = 1; i < 256; i++) ++ r[i] = g[i] = b[i] = i; ++} ++ ++ ++ ++static float hls_value (n1, n2, hue) ++ float n1,n2,hue; ++{ ++ if (hue>360.0) ++ hue-=360.0 ; ++ else if (hue<0.0) ++ hue+=360.0 ; ++ ++ if (hue<60.0) ++ return( n1+(n2-n1)*hue/60.0 ) ; ++ else if (hue<180.0) ++ return ( n2 ) ; ++ else if (hue<240.0) ++ return ( n1+(n2-n1)*(240.0-hue)/60.0 ) ; ++ else ++ return (n1) ; ++} ++ ++ ++ ++static void hls_to_rgb(h,l,s, r,g,b) ++ float h, l, s; ++ float *r, *g, *b; ++{ ++ static float m1, m2 ; ++ ++ if (l<=0.5) ++ m2=l*(1+s) ; ++ else ++ m2=l+s-l*s ; ++ m1=2.0*l-m2 ; ++ if (s==0.0) *r=*g=*b=l ; ++ else { ++ *r=hls_value(m1,m2,h+120.0) ; ++ *g=hls_value(m1,m2,h) ; ++ *b=hls_value(m1,m2,h-120.0) ; ++ } ++ ++} ++ ++ ++ ++static void make_huescale(char * r, char * g, char * b) ++{ ++ int j; ++ r[0] = g[0] = b[0] = 0; ++ for (j = 1; j<256; j++) ++ { ++ float fr, fg, fb; ++ hls_to_rgb((double)(256.0-j)*360.0/256.0, 0.5, 1.0, &fr, &fg, &fb); ++ r[j] = rint(255*fr); ++ g[j] = rint(255*fg); ++ b[j] = rint(255*fb); ++ } ++} ++ ++ ++ ++static void make_heatscale(char * r, char * g, char * b) ++{ ++ int j; ++ r[0] = g[0] = b[0] = 0; ++ for (j = 1; j<256; j++) ++ { ++ if(j<255/2) ++ r[j] = j*255/(255/2-1); ++ else ++ r[j]=255; ++ if (j>=255/2+255/3) ++ g[j] = 255; ++ else if (j>255/3) ++ g[j] = (j-255/3)*255/(255/2-1); ++ else ++ g[j] = 0; ++ if (j>255/2) ++ b[j] = (j-255/2)*255/(255-255/2-1); ++ else ++ b[j] = 0; ++ } ++} ++ ++ ++ ++static int load_colourmap(char *filestem, int max_colours, ++ char *r, char *g, char *b) ++{ ++ FILE * fp; ++ int numread=0; ++ char * filename; ++ char str[200]; ++ int num_colors; ++ /* ++ * Look for palette file in local directory ++ */ ++ ++ filename = (char*)alloca(strlen(filestem) + 5); ++ strcpy(filename, filestem); ++ strcat(filename, ".PAL"); /* Add the PAL suffix to the name specified */ ++ fp = fopen(filename,"r"); ++ if (!fp) { ++ /* ++ * If not found, try in $IM2HOME/etc/palettes ++ */ ++ char * im2home = (char*)getenv("IM2HOME"); ++ char * palette_subdirectory = "etc/palettes"; ++ char * fullfilename; ++ if (!im2home) ++ { ++ im2home = "/home/jewel/imagine2"; ++ fprintf(stderr,"IM2HOME environment variable not set -- using [%s]\n",im2home); ++ } ++ fullfilename = alloca(strlen(im2home)+strlen(palette_subdirectory)+strlen(filename)+5); ++ sprintf(fullfilename, "%s/%s/%s",im2home,palette_subdirectory,filename); ++ fp = fopen(fullfilename,"r"); ++ if (!fp) ++ { ++ fprintf(stderr,"Couldn't find any palette file -- looked for [%s] and [%s].\n", ++ filename,fullfilename); ++ perror("Last system error message was"); ++ return 0; ++ } ++ } ++ ++ strcpy(str,"(null)"); ++ if (!fscanf(fp,"%s\n",str) || strncmp(str,"Palette",7) != 0) { ++ fprintf(stderr,"error: First line of palette file should be `Palette', not [%s]\n", str); ++ return 0; ++ } ++ ++ fscanf(fp,"%[^\n]",str) ; /* Scan to end of line */ ++ fscanf (fp,"%d",&num_colors);/* Read the number of colours in the file */ ++ fgets(str,120,fp) ; /* Skip the text description, and general info lines */ ++ fgets(str,120,fp) ; ++ ++ while ((numread<max_colours)&&(numread<num_colors)) { ++ int rc, gc, bc; ++ fscanf (fp,"%d %d %d -", &rc, &gc, &bc) ; /* Get the (r,g,b) tuples */ ++ r[numread] = rc; ++ g[numread] = gc; ++ b[numread] = bc; ++ numread++; ++ fgets(str,120,fp) ; /* Skip the description, if present */ ++ } ++ ++ SetISTR(ISTR_INFO,"Read %d colors from palette file [%s]", numread, filename); ++ return (numread) ; /* Return the number of colours ACTUALLY READ */ ++} ++ ++#endif /* HAVE_HIPS */ +diff -ruN xv-3.10a-bugfixes/xvhips.h xv-3.10a-enhancements/xvhips.h +--- xv-3.10a-bugfixes/xvhips.h 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvhips.h 2005-04-25 08:34:14.000000000 -0700 +@@ -0,0 +1,154 @@ ++/* ++ * HIPL Picture Header Format Standard ++ * ++ * Michael Landy - 2/1/82 ++ */ ++ ++#define XHEADER ++#ifdef XHEADER ++struct extended { ++ char *name; ++ char *vals; ++ }; ++#endif ++ ++struct header { ++ char *orig_name; /* The originator of this sequence */ ++ char *seq_name; /* The name of this sequence */ ++ int num_frame; /* The number of frames in this sequence */ ++ char *orig_date; /* The date the sequence was originated */ ++ int rows; /* The number of rows in each image */ ++ int cols; /* The number of columns in each image */ ++ int bits_per_pixel; /* The number of significant bits per pixel */ ++ int bit_packing; /* Nonzero if bits were packed contiguously */ ++ int pixel_format; /* The format of each pixel, see below */ ++ char *seq_history; /* The sequence's history of transformations */ ++ char *seq_desc; /* Descriptive information */ ++#ifdef XHEADER ++ struct extended *xheader; ++#endif ++}; ++ ++/* ++ * Pixel Format Codes ++ */ ++ ++#define PFBYTE 0 /* Bytes interpreted as integers (8 bits) */ ++#define PFSHORT 1 /* Short integers (2 bytes) */ ++#define PFINT 2 /* Integers (4 bytes) */ ++#define PFFLOAT 3 /* Float's (4 bytes)*/ ++#define PFCOMPLEX 4 /* 2 Float's interpreted as (real,imaginary) */ ++#define PFASCII 5 /* ASCII rep, with linefeeds after each row */ ++#define PFDOUBLE 6 /* Double's (8 byte floats) */ ++#define PFDBLCOM 7 /* Double complex's (2 Double's) */ ++#define PFQUAD 10 /* quad-tree encoding (Mimaging) */ ++#define PFQUAD1 11 /* quad-tree encoding */ ++#define PFBHIST 12 /* histogram of byte image (using ints) */ ++#define PFSPAN 13 /* spanning tree format */ ++#define PLOT3D 24 /* plot-3d format */ ++#define PFINTPYR 50 /* integer pyramid */ ++#define PFFLOATPYR 51 /* float pyramid */ ++#define PFPOLYLINE 100 /* 2D points */ ++#define PFCOLVEC 101 /* Set of RGB triplets defining colours */ ++#define PFUKOOA 102 /* Data in standard UKOOA format */ ++#define PFTRAINING 104 /* Set of colour vector training examples */ ++#define PFTOSPACE 105 /* TOspace world model data structure */ ++#define PFSTEREO 106 /* Stereo sequence (l, r, l, r, ...) */ ++#define PFRGPLINE 107 /* 2D points with regions */ ++#define PFRGISPLINE 108 /* 2D points with regions and interfaces */ ++#define PFCHAIN 200 /* Chain code encoding (Mimaging) */ ++#define PFLUT 300 /* LUT format (uses Ints) (Mimaging) */ ++#define PFAHC 400 /* adaptive hierarchical encoding */ ++#define PFOCT 401 /* oct-tree encoding */ ++#define PFBT 402 /* binary tree encoding */ ++#define PFAHC3 403 /* 3-d adaptive hierarchical encoding */ ++#define PFBQ 404 /* binquad encoding */ ++#define PFRLED 500 /* run-length encoding */ ++#define PFRLEB 501 /* run-length encoding, line begins black */ ++#define PFRLEW 502 /* run-length encoding, line begins white */ ++#define PFPOLAR 600 /* rho-theta format (Mimaging) */ ++ ++/* ++ * Bit packing formats ++ */ ++ ++#define MSBFIRST 1 /* bit packing - most significant bit first */ ++#define LSBFIRST 2 /* bit packing - least significant bit first */ ++ ++#define FBUFLIMIT 30000 /* increase this if you use large PLOT3D ++ files */ ++ ++/* ++ * For general readability ++ */ ++ ++#ifndef TRUE ++# define TRUE 1 ++#endif ++ ++#ifndef FALSE ++# define FALSE 0 ++#endif ++ ++typedef long Boolean; ++extern char *strsave(), *memalloc(); ++ ++/* ++ * image and pyramid type declarations for the pyramid routines. ++ * ++ * The pyramid utilities are derived from code originally written by ++ * Raj Hingorani at SRI/David Sarnoff Research Institute. The original ++ * Gaussian and Laplacian pyramid algorithms were designed by Peter Burt (also ++ * currently at SRI/DSRC). See: Computer Graphics and Image Processing, ++ * Volume 16, pp. 20-51, 1981, and IEEE Transactions on Communications, ++ * Volume COM-31, pp. 532-540, 1983. ++ */ ++ ++#define MAXLEV 12 ++ ++ ++typedef struct { ++ float **ptr; ++ int nr; ++ int nc; ++} FIMAGE; ++ ++typedef struct { ++ int **ptr; ++ int nr; ++ int nc; ++} IIMAGE; ++ ++typedef FIMAGE FPYR[MAXLEV]; ++typedef IIMAGE IPYR[MAXLEV]; ++ ++typedef struct { ++ float *k; ++ int taps2; /* the number of taps from the center rightward, ++ total number is 2*taps2-1 */ ++} FILTER; ++ ++/* function definitions */ ++ ++float **_read_fimgstr(); ++int **_read_iimgstr(); ++float **_alloc_fimage(); ++int **_alloc_iimage(); ++ ++/* image macros */ ++ ++#ifndef MAX ++# define MAX(A,B) ((A) > (B) ? (A) : (B)) ++#endif /* MAX */ ++#ifndef MIN ++# define MIN(A,B) ((A) < (B) ? (A) : (B)) ++#endif /* MIN */ ++#ifndef ABS ++# define ABS(A) ((A) > 0 ? (A) : (-(A))) ++#endif /* ABS */ ++#ifndef BETWEEN ++# define BETWEEN(A,B,C) (((A) < (B)) ? (B) : (((A) > (C)) ? (C) : (A))) ++#endif /* BETWEEN */ ++#ifndef SIGN ++# define SIGN(A,B) (((B) > 0) ? (A) : (-(A))) ++#endif /* SIGN */ +diff -ruN xv-3.10a-bugfixes/xvimage.c xv-3.10a-enhancements/xvimage.c +--- xv-3.10a-bugfixes/xvimage.c 2005-03-31 07:23:39.000000000 -0800 ++++ xv-3.10a-enhancements/xvimage.c 2005-04-17 23:00:10.000000000 -0700 +@@ -21,6 +21,16 @@ + * int LoadPad(pinfo, fname); + */ + ++/* The following switch should better be provided at runtime for ++ * comparison purposes. ++ * At the moment it's only compile time, unfortunately. ++ * Who can make adaptions for use as a runtime switch by a menu option? ++ * [GRR 19980607: now via do_fixpix_smooth global; macro renamed to ENABLE_] ++ * [see http://sylvana.net/fixpix/ for home page, further info] ++ */ ++/* #define ENABLE_FIXPIX_SMOOTH */ /* GRR 19980607: moved into xv.h */ ++ ++#define NEEDSDIR /* for S_IRUSR|S_IWUSR */ + #include "copyright.h" + + #include "xv.h" +@@ -36,7 +46,9 @@ + static int doAutoCrop24 PARM((void)); + static void floydDitherize1 PARM((XImage *, byte *, int, int, int, + byte *, byte *,byte *)); ++#if 0 /* NOTUSED */ + static int highbit PARM((unsigned long)); ++#endif + + static int doPadSolid PARM((char *, int, int, int, int)); + static int doPadBggen PARM((char *, int, int, int, int)); +@@ -46,6 +58,267 @@ + static int ReadImageFile1 PARM((char *, PICINFO *)); + + ++/* The following array represents the pixel values for each shade ++ * of the primary color components. ++ * If 'p' is a pointer to a source image rgb-byte-triplet, we can ++ * construct the output pixel value simply by 'oring' together ++ * the corresponding components: ++ * ++ * unsigned char *p; ++ * unsigned long pixval; ++ * ++ * pixval = screen_rgb[0][*p++]; ++ * pixval |= screen_rgb[1][*p++]; ++ * pixval |= screen_rgb[2][*p++]; ++ * ++ * This is both efficient and generic, since the only assumption ++ * is that the primary color components have separate bits. ++ * The order and distribution of bits does not matter, and we ++ * don't need additional variables and shifting/masking code. ++ * The array size is 3 KBytes total and thus very reasonable. ++ */ ++ ++static unsigned long screen_rgb[3][256]; ++ ++/* The following array holds the exact color representations ++ * reported by the system. ++ * This is useful for less than 24 bit deep displays as a base ++ * for additional dithering to get smoother output. ++ */ ++ ++static byte screen_set[3][256]; ++ ++/* The following routine initializes the screen_rgb and screen_set ++ * arrays. ++ * Since it is executed only once per program run, it does not need ++ * to be super-efficient. ++ * ++ * The method is to draw points in a pixmap with the specified shades ++ * of primary colors and then get the corresponding XImage pixel ++ * representation. ++ * Thus we can get away with any Bit-order/Byte-order dependencies. ++ * ++ * The routine uses some global X variables: theDisp, theScreen, ++ * and dispDEEP. Adapt these to your application as necessary. ++ * I've not passed them in as parameters, since for other platforms ++ * than X these may be different (see vfixpix.c), and so the ++ * screen_init() interface is unique. ++ * ++ * BUG: I've read in the "Xlib Programming Manual" from O'Reilly & ++ * Associates, that the DefaultColormap in TrueColor might not ++ * provide the full shade representation in XAllocColor. ++ * In this case one had to provide a 'best' colormap instead. ++ * However, my tests with Xaccel on a Linux-Box with a Mach64 ++ * card were fully successful, so I leave that potential problem ++ * to you at the moment and would appreciate any suggestions... ++ */ ++ ++static void screen_init() ++{ ++ static int init_flag; /* assume auto-init as 0 */ ++ Pixmap check_map; ++ GC check_gc; ++ XColor check_col; ++ XImage *check_image; ++ int ci, i; ++ ++ if (init_flag) return; ++ init_flag = 1; ++ ++ check_map = XCreatePixmap(theDisp, RootWindow(theDisp,theScreen), ++ 1, 1, dispDEEP); ++ check_gc = XCreateGC(theDisp, check_map, 0, NULL); ++ for (ci = 0; ci < 3; ci++) { ++ for (i = 0; i < 256; i++) { ++ check_col.red = 0; ++ check_col.green = 0; ++ check_col.blue = 0; ++ /* Do proper upscaling from unsigned 8 bit (image data values) ++ to unsigned 16 bit (X color representation). */ ++ ((unsigned short *)&check_col.red)[ci] = (unsigned short)((i << 8) | i); ++ if (theVisual->class == TrueColor) ++ XAllocColor(theDisp, theCmap, &check_col); ++ else ++ xvAllocColor(theDisp, theCmap, &check_col); ++ screen_set[ci][i] = ++ (((unsigned short *)&check_col.red)[ci] >> 8) & 0xff; ++ XSetForeground(theDisp, check_gc, check_col.pixel); ++ XDrawPoint(theDisp, check_map, check_gc, 0, 0); ++ check_image = XGetImage(theDisp, check_map, 0, 0, 1, 1, ++ AllPlanes, ZPixmap); ++ if (check_image) { ++ switch (check_image->bits_per_pixel) { ++ case 8: ++ screen_rgb[ci][i] = *(CARD8 *)check_image->data; ++ break; ++ case 16: ++ screen_rgb[ci][i] = *(CARD16 *)check_image->data; ++ break; ++ case 24: ++ screen_rgb[ci][i] = ++ ((unsigned long)*(CARD8 *)check_image->data << 16) | ++ ((unsigned long)*(CARD8 *)(check_image->data + 1) << 8) | ++ (unsigned long)*(CARD8 *)(check_image->data + 2); ++ break; ++ case 32: ++ screen_rgb[ci][i] = *(CARD32 *)check_image->data; ++ break; ++ } ++ XDestroyImage(check_image); ++ } ++ } ++ } ++ XFreeGC(theDisp, check_gc); ++ XFreePixmap(theDisp, check_map); ++} ++ ++ ++#ifdef ENABLE_FIXPIX_SMOOTH ++ ++/* The following code is based in part on: ++ * ++ * 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. ++ */ ++ ++/* 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.) ++ * ++ * We provide (#columns + 2) entries per component; the extra entry at each ++ * end saves us from special-casing the first and last pixels. ++ */ ++ ++typedef INT16 FSERROR; /* 16 bits should be enough */ ++typedef int LOCFSERROR; /* use 'int' for calculation temps */ ++ ++typedef struct { byte *colorset; ++ FSERROR *fserrors; ++ } FSBUF; ++ ++/* Floyd-Steinberg initialization function. ++ * ++ * It is called 'fs2_init' since it's specialized for our purpose and ++ * could be embedded in a more general FS-package. ++ * ++ * Returns a malloced FSBUF pointer which has to be passed as first ++ * parameter to subsequent 'fs2_dither' calls. ++ * The FSBUF structure does not need to be referenced by the calling ++ * application, it can be treated from the app like a void pointer. ++ * ++ * The current implementation does only require to free() this returned ++ * pointer after processing. ++ * ++ * Returns NULL if malloc fails. ++ * ++ * NOTE: The FSBUF structure is designed to allow the 'fs2_dither' ++ * function to work with an *arbitrary* number of color components ++ * at runtime! This is an enhancement over the IJG code base :-). ++ * Only fs2_init() specifies the (maximum) number of components. ++ */ ++ ++static FSBUF *fs2_init(width) ++int width; ++{ ++ FSBUF *fs; ++ FSERROR *p; ++ ++ fs = (FSBUF *) ++ malloc(sizeof(FSBUF) * 3 + ((size_t)width + 2) * sizeof(FSERROR) * 3); ++ if (fs == 0) return fs; ++ ++ fs[0].colorset = screen_set[0]; ++ fs[1].colorset = screen_set[1]; ++ fs[2].colorset = screen_set[2]; ++ ++ p = (FSERROR *)(fs + 3); ++ memset(p, 0, ((size_t)width + 2) * sizeof(FSERROR) * 3); ++ ++ fs[0].fserrors = p; ++ fs[1].fserrors = p + 1; ++ fs[2].fserrors = p + 2; ++ ++ return fs; ++} ++ ++/* Floyd-Steinberg dithering function. ++ * ++ * NOTE: ++ * (1) The image data referenced by 'ptr' is *overwritten* (input *and* ++ * output) to allow more efficient implementation. ++ * (2) Alternate FS dithering is provided by the sign of 'nc'. Pass in ++ * a negative value for right-to-left processing. The return value ++ * provides the right-signed value for subsequent calls! ++ * (3) This particular implementation assumes *no* padding between lines! ++ * Adapt this if necessary. ++ */ ++ ++static int fs2_dither(fs, ptr, nc, num_rows, num_cols) ++FSBUF *fs; ++byte *ptr; ++int nc, num_rows, num_cols; ++{ ++ int abs_nc, ci, row, col; ++ LOCFSERROR delta, cur, belowerr, bpreverr; ++ byte *dataptr, *colsetptr; ++ FSERROR *errorptr; ++ ++ if ((abs_nc = nc) < 0) abs_nc = -abs_nc; ++ for (row = 0; row < num_rows; row++) { ++ for (ci = 0; ci < abs_nc; ci++, ptr++) { ++ dataptr = ptr; ++ colsetptr = fs[ci].colorset; ++ errorptr = fs[ci].fserrors; ++ if (nc < 0) { ++ dataptr += (num_cols - 1) * abs_nc; ++ errorptr += (num_cols + 1) * abs_nc; ++ } ++ cur = belowerr = bpreverr = 0; ++ for (col = 0; col < num_cols; col++) { ++ cur += errorptr[nc]; ++ cur += 8; cur >>= 4; ++ if ((cur += *dataptr) < 0) cur = 0; ++ else if (cur > 255) cur = 255; ++ *dataptr = cur & 0xff; ++ cur -= colsetptr[cur]; ++ delta = cur << 1; cur += delta; ++ bpreverr += cur; cur += delta; ++ belowerr += cur; cur += delta; ++ errorptr[0] = (FSERROR)bpreverr; ++ bpreverr = belowerr; ++ belowerr = delta >> 1; ++ dataptr += nc; ++ errorptr += nc; ++ } ++ errorptr[0] = (FSERROR)bpreverr; ++ } ++ ptr += (num_cols - 1) * abs_nc; ++ nc = -nc; ++ } ++ return nc; ++} ++ ++#endif /* ENABLE_FIXPIX_SMOOTH */ ++ + + #define DO_CROP 0 + #define DO_ZOOM 1 +@@ -1348,7 +1621,7 @@ + SetISTR(ISTR_WARNING, "Invalid image dimensions for dithering"); + return (byte *)NULL; + } +- ++ + outpic = (byte *) malloc((size_t) npixels); + if (!outpic) return outpic; + +@@ -1838,7 +2111,7 @@ + unsigned int wide, high; + { + /* +- * this has to do the none-to-simple bit of converting the data in 'pic24' ++ * This has to do the none-too-simple bit of converting the data in 'pic24' + * into something usable by X. + * + * There are two major approaches: if we're displaying on a TrueColor +@@ -1852,7 +2125,7 @@ + * mode. (In that by this point, a 3/3/2 standard colormap has been + * created for our use (though all 256 colors may not be unique...), and + * we're just going to display the 24-bit picture by dithering with those +- * colors ++ * colors.) + * + */ + +@@ -1890,33 +2163,17 @@ + /* Non-ColorMapped Visuals: TrueColor, DirectColor */ + /************************************************************************/ + +- unsigned long r, g, b, rmask, gmask, bmask, xcol; +- int rshift, gshift, bshift, bperpix, bperline, border, cshift; +- int maplen; ++ unsigned long xcol; ++ int bperpix, bperline; + byte *imagedata, *lip, *ip, *pp; + + +- /* compute various shifting constants that we'll need... */ +- +- rmask = theVisual->red_mask; +- gmask = theVisual->green_mask; +- bmask = theVisual->blue_mask; +- +- rshift = 7 - highbit(rmask); +- gshift = 7 - highbit(gmask); +- bshift = 7 - highbit(bmask); +- +- maplen = theVisual->map_entries; +- if (maplen>256) maplen=256; +- cshift = 7 - highbit((u_long) (maplen-1)); +- + xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, + wide, high, 32, 0); + if (!xim) FatalError("couldn't create X image!"); + + bperline = xim->bytes_per_line; + bperpix = xim->bits_per_pixel; +- border = xim->byte_order; + + imagedata = (byte *) malloc((size_t) (high * bperline)); + if (!imagedata) FatalError("couldn't malloc imagedata"); +@@ -1930,85 +2187,141 @@ + FatalError(buf); + } + ++ screen_init(); + +- lip = imagedata; pp = pic24; +- for (i=0; i<high; i++, lip+=bperline) { +- for (j=0, ip=lip; j<wide; j++) { +- r = *pp++; g = *pp++; b = *pp++; +- +- /* shift r,g,b so that high bit of 8-bit color specification is +- * aligned with high bit of r,g,b-mask in visual, +- * AND each component with its mask, +- * and OR the three components together +- */ +- +- if (theVisual->class == DirectColor) { +- r = (u_long) directConv[(r>>cshift) & 0xff] << cshift; +- g = (u_long) directConv[(g>>cshift) & 0xff] << cshift; +- b = (u_long) directConv[(b>>cshift) & 0xff] << cshift; +- } +- +- +- /* shift the bits around */ +- if (rshift<0) r = r << (-rshift); +- else r = r >> rshift; +- +- if (gshift<0) g = g << (-gshift); +- else g = g >> gshift; +- +- if (bshift<0) b = b << (-bshift); +- else b = b >> bshift; +- +- r = r & rmask; +- g = g & gmask; +- b = b & bmask; +- +- xcol = r | g | b; +- +- if (bperpix == 32) { +- if (border == MSBFirst) { +- *ip++ = (xcol>>24) & 0xff; +- *ip++ = (xcol>>16) & 0xff; +- *ip++ = (xcol>>8) & 0xff; +- *ip++ = xcol & 0xff; +- } +- else { /* LSBFirst */ +- *ip++ = xcol & 0xff; +- *ip++ = (xcol>>8) & 0xff; +- *ip++ = (xcol>>16) & 0xff; +- *ip++ = (xcol>>24) & 0xff; +- } +- } +- +- else if (bperpix == 24) { +- if (border == MSBFirst) { +- *ip++ = (xcol>>16) & 0xff; +- *ip++ = (xcol>>8) & 0xff; +- *ip++ = xcol & 0xff; +- } +- else { /* LSBFirst */ +- *ip++ = xcol & 0xff; +- *ip++ = (xcol>>8) & 0xff; +- *ip++ = (xcol>>16) & 0xff; +- } +- } ++#ifdef ENABLE_FIXPIX_SMOOTH ++ if (do_fixpix_smooth) { ++#if 0 ++ /* If we wouldn't have to save the original pic24 image data, ++ * the following code would do the dither job by overwriting ++ * the image data, and the normal render code would then work ++ * without any change on that data. ++ * Unfortunately, this approach would hurt the xv assumptions... ++ */ ++ if (bperpix < 24) { ++ FSBUF *fs = fs2_init(wide); ++ if (fs) { ++ fs2_dither(fs, pic24, 3, high, wide); ++ free(fs); ++ } ++ } ++#else ++ /* ...so we have to take a different approach with linewise ++ * dithering/rendering in a loop using a temporary line buffer. ++ */ ++ if (bperpix < 24) { ++ FSBUF *fs = fs2_init(wide); ++ if (fs) { ++ byte *row_buf = malloc((size_t)wide * 3); ++ if (row_buf) { ++ int nc = 3; ++ byte *picp = pic24; lip = imagedata; ++ ++ switch (bperpix) { ++ case 8: ++ for (i=0; i<high; i++, lip+=bperline, picp+=(size_t)wide*3) { ++ memcpy(row_buf, picp, (size_t)wide * 3); ++ nc = fs2_dither(fs, row_buf, nc, 1, wide); ++ for (j=0, ip=lip, pp=row_buf; j<wide; j++) { ++ xcol = screen_rgb[0][*pp++]; ++ xcol |= screen_rgb[1][*pp++]; ++ xcol |= screen_rgb[2][*pp++]; ++ *ip++ = xcol & 0xff; ++ } ++ } ++ break; ++ ++ case 16: ++ for (i=0; i<high; i++, lip+=bperline, picp+=(size_t)wide*3) { ++ CARD16 *ip16 = (CARD16 *)lip; ++ memcpy(row_buf, picp, (size_t)wide * 3); ++ nc = fs2_dither(fs, row_buf, nc, 1, wide); ++ for (j=0, pp=row_buf; j<wide; j++) { ++ xcol = screen_rgb[0][*pp++]; ++ xcol |= screen_rgb[1][*pp++]; ++ xcol |= screen_rgb[2][*pp++]; ++ *ip16++ = (CARD16)xcol; ++ } ++ } ++ break; ++ } /* end switch */ ++ ++ free(row_buf); ++ free(fs); + +- else if (bperpix == 16) { +- if (border == MSBFirst) { +- *ip++ = (xcol>>8) & 0xff; +- *ip++ = xcol & 0xff; +- } +- else { /* LSBFirst */ +- *ip++ = xcol & 0xff; +- *ip++ = (xcol>>8) & 0xff; ++ return xim; + } +- } +- +- else if (bperpix == 8) { +- *ip++ = xcol & 0xff; +- } ++ free(fs); ++ } + } ++#endif /* 0? */ + } ++#endif /* ENABLE_FIXPIX_SMOOTH */ ++ ++ lip = imagedata; pp = pic24; ++ ++ switch (bperpix) { ++ case 8: ++ for (i=0; i<high; i++, lip+=bperline) { ++ for (j=0, ip=lip; j<wide; j++) { ++ xcol = screen_rgb[0][*pp++]; ++ xcol |= screen_rgb[1][*pp++]; ++ xcol |= screen_rgb[2][*pp++]; ++ *ip++ = xcol & 0xff; ++ } ++ } ++ break; ++ ++ case 16: ++ for (i=0; i<high; i++, lip+=bperline) { ++ CARD16 *ip16 = (CARD16 *)lip; ++ for (j=0; j<wide; j++) { ++ xcol = screen_rgb[0][*pp++]; ++ xcol |= screen_rgb[1][*pp++]; ++ xcol |= screen_rgb[2][*pp++]; ++ *ip16++ = (CARD16)xcol; ++ } ++ } ++ break; ++ ++ case 24: ++ for (i=0; i<high; i++, lip+=bperline) { ++ for (j=0, ip=lip; j<wide; j++) { ++ xcol = screen_rgb[0][*pp++]; ++ xcol |= screen_rgb[1][*pp++]; ++ xcol |= screen_rgb[2][*pp++]; ++#ifdef USE_24BIT_ENDIAN_FIX ++ if (border == MSBFirst) { ++ *ip++ = (xcol>>16) & 0xff; ++ *ip++ = (xcol>>8) & 0xff; ++ *ip++ = xcol & 0xff; ++ } ++ else { /* LSBFirst */ ++ *ip++ = xcol & 0xff; ++ *ip++ = (xcol>>8) & 0xff; ++ *ip++ = (xcol>>16) & 0xff; ++ } ++#else /* GRR: this came with the FixPix patch, but I don't think it's right */ ++ *ip++ = (xcol >> 16) & 0xff; /* (no way to test, however, so */ ++ *ip++ = (xcol >> 8) & 0xff; /* it's left enabled by default) */ ++ *ip++ = xcol & 0xff; ++#endif ++ } ++ } ++ break; ++ ++ case 32: ++ for (i=0; i<high; i++, lip+=bperline) { ++ CARD32 *ip32 = (CARD32 *)lip; ++ for (j=0; j<wide; j++) { ++ xcol = screen_rgb[0][*pp++]; ++ xcol |= screen_rgb[1][*pp++]; ++ xcol |= screen_rgb[2][*pp++]; ++ *ip32++ = (CARD32)xcol; ++ } ++ } ++ break; ++ } /* end switch */ + } + + else { +@@ -2458,6 +2771,7 @@ + + + /***********************/ ++#if 0 /* NOTUSED */ + static int highbit(ul) + unsigned long ul; + { +@@ -2470,6 +2784,7 @@ + for (i=31; ((ul & hb) == 0) && i>=0; i--, ul<<=1); + return i; + } ++#endif /* 0 - NOTUSED */ + + + +@@ -2680,6 +2995,9 @@ + char *str; + int wide, high, opaque,omode; + { ++#ifndef USE_MKSTEMP ++ int tmpfd; ++#endif + int i; + byte *bgpic24; + char syscmd[512], fname[128], errstr[512]; +@@ -2705,6 +3023,13 @@ + close(mkstemp(fname)); + #else + mktemp(fname); ++ tmpfd = open(fname, O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR); ++ if (tmpfd < 0) { ++ sprintf(errstr, "Error: can't create temporary file %s", fname); ++ ErrPopUp(errstr, "\nDoh!"); ++ return 0; ++ } ++ close(tmpfd); + #endif + + /* run bggen to generate the background */ +@@ -2978,7 +3303,7 @@ + + ftype = ReadFileType(name); + +- if (ftype == RFT_COMPRESS) { /* handle compressed/gzipped files */ ++ if ((ftype == RFT_COMPRESS) || (ftype == RFT_BZIP2)) { /* handle .Z,gz,bz2 */ + #ifdef VMS + basefname[0] = '\0'; + strcpy(basefname, name); /* remove trailing .Z */ +@@ -2988,7 +3313,7 @@ + uncName = name; + #endif + +- if (UncompressFile(uncName, uncompname)) { ++ if (UncompressFile(uncName, uncompname, ftype)) { + ftype = ReadFileType(uncompname); + readname = uncompname; + } +@@ -3029,9 +3354,3 @@ + + return 1; + } +- +- +- +- +- +- +diff -ruN xv-3.10a-bugfixes/xvinfo.c xv-3.10a-enhancements/xvinfo.c +--- xv-3.10a-bugfixes/xvinfo.c 2004-05-16 18:03:43.000000000 -0700 ++++ xv-3.10a-enhancements/xvinfo.c 2005-05-01 00:05:53.000000000 -0700 +@@ -265,7 +265,7 @@ + if (stnum == ISTR_WARNING && !ctrlUp && !infoUp && !anyBrowUp && + strlen(istrs[stnum])) { + OpenAlert(istrs[stnum]); +- sleep(3); ++ sleep(1); /* was 3, but _really_ slow for TIFFs with unknown tags... */ + CloseAlert(); + } + } +diff -ruN xv-3.10a-bugfixes/xvjpeg.c xv-3.10a-enhancements/xvjpeg.c +--- xv-3.10a-bugfixes/xvjpeg.c 2005-03-27 16:23:06.000000000 -0800 ++++ xv-3.10a-enhancements/xvjpeg.c 2005-04-17 14:45:28.000000000 -0700 +@@ -51,11 +51,21 @@ + static void clickJD PARM((int, int)); + static void doCmd PARM((int)); + static void writeJPEG PARM((void)); ++#if JPEG_LIB_VERSION > 60 ++METHODDEF(void) xv_error_exit PARM((j_common_ptr)); ++METHODDEF(void) xv_error_output PARM((j_common_ptr)); ++METHODDEF(void) xv_prog_meter PARM((j_common_ptr)); ++#else + METHODDEF void xv_error_exit PARM((j_common_ptr)); + METHODDEF void xv_error_output PARM((j_common_ptr)); + METHODDEF void xv_prog_meter PARM((j_common_ptr)); ++#endif + static unsigned int j_getc PARM((j_decompress_ptr)); ++#if JPEG_LIB_VERSION > 60 ++METHODDEF(boolean) xv_process_comment PARM((j_decompress_ptr)); ++#else + METHODDEF boolean xv_process_comment PARM((j_decompress_ptr)); ++#endif + static int writeJFIF PARM((FILE *, byte *, int,int,int)); + + +@@ -85,10 +95,10 @@ + + XSelectInput(theDisp, jpegW, ExposureMask | ButtonPressMask | KeyPressMask); + +- DCreate(&qDial, jpegW, 10, 10, 80, 100, 1, 100, 75, 5, ++ DCreate(&qDial, jpegW, 10, 10, 80, 100, 1.0, 100.0, 75.0, 1.0, 5.0, + infofg, infobg, hicol, locol, "Quality", "%"); + +- DCreate(&smDial, jpegW, 120, 10, 80, 100, 0, 100, 0, 5, ++ DCreate(&smDial, jpegW, 120, 10, 80, 100, 0.0, 100.0, 0.0, 1.0, 5.0, + infofg, infobg, hicol, locol, "Smoothing", "%"); + + BTCreate(&jbut[J_BOK], jpegW, JWIDE-180-1, JHIGH-10-BUTTH-1, 80, BUTTH, +@@ -415,7 +425,11 @@ + + + /**************************************************/ +-METHODDEF void xv_error_exit(cinfo) ++#if JPEG_LIB_VERSION > 60 ++METHODDEF(void) xv_error_exit(cinfo) ++#else ++METHODDEF void xv_error_exit(cinfo) ++#endif + j_common_ptr cinfo; + { + my_error_ptr myerr; +@@ -427,7 +441,11 @@ + + + /**************************************************/ +-METHODDEF void xv_error_output(cinfo) ++#if JPEG_LIB_VERSION > 60 ++METHODDEF(void) xv_error_output(cinfo) ++#else ++METHODDEF void xv_error_output(cinfo) ++#endif + j_common_ptr cinfo; + { + my_error_ptr myerr; +@@ -441,7 +459,11 @@ + + + /**************************************************/ +-METHODDEF void xv_prog_meter(cinfo) ++#if JPEG_LIB_VERSION > 60 ++METHODDEF(void) xv_prog_meter(cinfo) ++#else ++METHODDEF void xv_prog_meter(cinfo) ++#endif + j_common_ptr cinfo; + { + struct jpeg_progress_mgr *prog; +@@ -706,7 +728,11 @@ + + + /**************************************************/ +-METHODDEF boolean xv_process_comment(cinfo) ++#if JPEG_LIB_VERSION > 60 ++METHODDEF(boolean) xv_process_comment(cinfo) ++#else ++METHODDEF boolean xv_process_comment(cinfo) ++#endif + j_decompress_ptr cinfo; + { + int length, hasnull; +@@ -794,8 +820,8 @@ + + + jpeg_set_defaults(&cinfo); +- jpeg_set_quality(&cinfo, qDial.val, TRUE); +- cinfo.smoothing_factor = smDial.val; ++ jpeg_set_quality(&cinfo, (int)qDial.val, TRUE); ++ cinfo.smoothing_factor = (int)smDial.val; + + + jpeg_start_compress(&cinfo, TRUE); +@@ -804,7 +830,7 @@ + /*** COMMENT HANDLING ***/ + + sprintf(xvcmt, "%sXV %s Quality = %d, Smoothing = %d\n", +- CREATOR_STR, REVDATE, qDial.val, smDial.val); ++ CREATOR_STR, REVDATE, (int)qDial.val, (int)smDial.val); + + if (picComments) { /* append XV comment */ + char *sp, *sp1; int done; +@@ -866,4 +892,27 @@ + + + ++ ++/*******************************************/ ++void ++VersionInfoJPEG() /* GRR 19980605, 19980607 */ ++{ ++ int major = JPEG_LIB_VERSION / 10; ++ int minor = JPEG_LIB_VERSION % 10; ++ char minoralpha[2]; ++ ++ if (minor) { ++ minoralpha[0] = (char)(minor - 1 + 'a'); ++ minoralpha[1] = '\0'; ++ } else ++ minoralpha[0] = '\0'; ++ ++/* fprintf(stderr, " Compiled with libjpeg %d.%d.\n", major, minor); */ ++ fprintf(stderr, " Compiled with libjpeg %d%s.\n", major, minoralpha); ++} ++ ++ ++ ++ ++ + #endif /* HAVE_JPEG */ +diff -ruN xv-3.10a-bugfixes/xvmag.c xv-3.10a-enhancements/xvmag.c +--- xv-3.10a-bugfixes/xvmag.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvmag.c 2005-04-17 22:56:58.000000000 -0700 +@@ -0,0 +1,866 @@ ++/* ++ * xvmag.c - load routine for `MAG' format pictures. ++ * ++ * The `MAG' format is used by many Japanese personal computer users. ++ * This program is based on MAGBIBLE.DOC which is the specification ++ * for `MAG' format written by Woody RINN. It is written in Japanese, ++ * and exists in some anon-ftp sites. ++ */ ++ ++#include "xv.h" ++#include <setjmp.h> ++ ++#ifdef HAVE_MAG ++ ++typedef unsigned short data16; ++ ++struct mag { ++ jmp_buf jmp; ++ FILE *fp; ++ long fsize; ++ int m_256, m_dig, m_8, m_200; ++ int x1, y1, x2, y2, left_pad, right_pad; ++ int p_width, p_height, width, height; ++ long h_off, a_off, a_size, b_off, b_size, p_off, p_size; ++ byte *a, *b, *p; ++}; ++ ++static void mag_open_file PARM((struct mag*, char*)); ++static void mag_read_check_data PARM((struct mag*)); ++static void mag_read_comment PARM((struct mag*, char**)); ++static void mag_read_header PARM((struct mag*)); ++static void mag_read_palette PARM((struct mag*, byte*, byte*, byte*)); ++static void mag_read_flags PARM((struct mag*)); ++static void mag_read_pixel_data PARM((struct mag*)); ++static void mag_expand_body PARM((struct mag*, byte**)); ++ ++static void mag_compress_data PARM((struct mag*, byte*)); ++static void mag_write_check_data PARM((struct mag*)); ++static void mag_write_comment PARM((struct mag*, char *)); ++static void mag_write_palette PARM((struct mag*, int, ++ byte*, byte*, byte*, int)); ++static void mag_write_flags PARM((struct mag*)); ++static void mag_write_pixel_data PARM((struct mag*)); ++static void mag_write_header PARM((struct mag*)); ++static void mag_set_double_word PARM((long, byte *)); ++ ++static void mag_init_info PARM((struct mag*)); ++static void mag_cleanup_mag_info PARM((struct mag*, int)); ++static void mag_cleanup_pinfo PARM((PICINFO*)); ++static void mag_memory_error PARM((char*, char*)); ++static void mag_error PARM((struct mag*, int)); ++static void mag_file_error PARM((struct mag*, int)); ++static void mag_file_warning PARM((struct mag*, int)); ++static void mag_show_struct PARM((struct mag*)); ++static void *mag_malloc PARM((size_t, char*)); ++static void *mag_realloc PARM((void*, size_t, char*)); ++ ++ ++static char *mag_id = "MAKI02 "; ++static struct{ ++ int dx, dy; ++}points[16] = { ++ { 0, 0}, { 1, 0}, { 2, 0}, { 4, 0}, ++ { 0, 1}, { 1, 1}, ++ { 0, 2}, { 1, 2}, { 2, 2}, ++ { 0, 4}, { 1, 4}, { 2, 4}, ++ { 0, 8}, { 1, 8}, { 2, 8}, ++ { 0, 16}, ++}; ++static int try[15] = {1, 4, 5, 6, 7, 9, 10, 2, 8, 11, 12, 13, 14, 3, 15}; ++ ++static char *mag_msgs[] = { ++ NULL, ++#define MAG_OPEN 1 ++ "can't open file", ++#define MAG_CORRUPT 2 ++ "file currupted.", ++#define MAG_FORMAT 3 ++ "not MAG format.", ++#define MAG_WRITE 4 ++ "write failed.", ++}; ++ ++ ++#define H4(x) (((int) (x) >> 4) & 0x0f) /* operates on a byte */ ++#define L4(x) ((x) & 0x0f) ++#define H8(x) (((x) >> 8) & 0xff) /* operates on a data16 */ ++#define L8(x) ((x) & 0xff) ++ ++#define error(msgnum) longjmp(mi->jmp, msgnum) ++ ++ ++/* The main routine to load a MAG file. */ ++int LoadMAG(fname, pinfo) ++ char *fname; ++ PICINFO *pinfo; ++{ ++ struct mag mag; ++ int e; ++ ++ if(DEBUG) fputs("LoadMAG:\n", stderr); ++ ++ pinfo->comment = NULL; ++ mag_init_info(&mag); ++ if((e = setjmp(mag.jmp)) != 0){ ++ /* When an error occurs, comes here. */ ++ mag_cleanup_mag_info(&mag, 0); ++ mag_cleanup_pinfo(pinfo); ++ return 0; ++ } ++ ++ mag_open_file(&mag, fname); ++ mag_read_check_data(&mag); ++ mag_read_comment(&mag, &pinfo->comment); ++ mag_read_header(&mag); ++ mag_read_palette(&mag, pinfo->r, pinfo->g, pinfo->b); ++ mag_read_flags(&mag); ++ mag_read_pixel_data(&mag); ++ mag_expand_body(&mag, &pinfo->pic); ++ ++ pinfo->w = pinfo->normw = mag.width; ++ pinfo->h = pinfo->normh = mag.height; ++ pinfo->type = PIC8; ++ pinfo->frmType = F_MAG; ++ pinfo->colType = F_FULLCOLOR; ++ sprintf(pinfo->fullInfo, "MAG, %d colors%s (%ld bytes)", ++ mag.m_256 ? 256 : (mag.m_8 ? 8 : 16), ++ mag.m_200 ? ", aspect 0.5" : "", mag.fsize); ++ sprintf(pinfo->shrtInfo, "%dx%d MAG", mag.width, mag.height); ++ if(mag.m_200) ++ normaspect = 0.5; ++ ++ mag_cleanup_mag_info(&mag, 0); ++ return 1; ++} ++ ++static void mag_open_file(mi, fname) ++ struct mag *mi; ++ char *fname; ++{ ++ if((mi->fp = fopen(fname, "rb")) == NULL) ++ mag_file_error(mi, MAG_OPEN); ++ fseek(mi->fp, (size_t) 0, SEEK_END); ++ mi->fsize = ftell(mi->fp); ++ fseek(mi->fp, (size_t) 0, SEEK_SET); ++} ++ ++static void mag_read_check_data(mi) ++ struct mag *mi; ++{ ++ char buffer[8]; ++ ++ if(fread(buffer, (size_t) 8, (size_t) 1, mi->fp) != 1) ++ mag_file_error(mi, MAG_CORRUPT); ++ if(strncmp(buffer, mag_id, (size_t) 8) != 0) ++ mag_error(mi, MAG_FORMAT); ++} ++ ++static void mag_read_comment(mi, p) ++ struct mag *mi; ++ char **p; ++{ ++ int max = -1, i = 0; ++ int c; ++ ++ while((c = fgetc(mi->fp)) != EOF){ ++ if(c == 0x1a) ++ break; ++ if(max < i){ ++ max += 16; ++ *p = mag_realloc(*p, (size_t) max + 1, "mag_read_comment#1"); ++ } ++ (*p)[i++] = c; ++ } ++ ++ if(c == EOF) ++ mag_file_error(mi, MAG_CORRUPT); ++ ++ if(max < i){ ++ *p = mag_realloc(*p, (size_t) max + 2, "mag_read_comment#2"); ++ } ++ if(i > 24){ ++ (*p)[i] = '\0'; ++ strcpy(*p, &(*p)[24]); ++ }else{ ++ (*p)[0] = '\0'; ++ } ++} ++ ++static void mag_read_header(mi) ++ struct mag *mi; ++{ ++ byte buf[32]; ++ ++ mi->h_off = ftell(mi->fp); ++ ++ if(fread(buf, (size_t) 32, (size_t) 1, mi->fp) != 1) ++ mag_file_error(mi, MAG_CORRUPT); ++ ++ mi->m_256 = buf[3] & 0x80; ++ mi->m_dig = buf[3] & 0x04; ++ mi->m_8 = buf[3] & 0x02; ++ mi->m_200 = buf[3] & 0x01; ++ ++ mi->x1 = buf[ 4] + buf[ 5] * 256; ++ mi->y1 = buf[ 6] + buf[ 7] * 256; ++ mi->x2 = buf[ 8] + buf[ 9] * 256; ++ mi->y2 = buf[10] + buf[11] * 256; ++ ++#define get_dword(a, b, c, d) \ ++ ((long)(a) << 24 | (long)(b) << 16 | (long)(c) << 8 | (long)(d)) ++ ++ mi->a_off = get_dword(buf[15], buf[14], buf[13], buf[12]); ++ mi->b_off = get_dword(buf[19], buf[18], buf[17], buf[16]); ++ mi->b_size = get_dword(buf[23], buf[22], buf[21], buf[20]); ++ mi->p_off = get_dword(buf[27], buf[26], buf[25], buf[24]); ++ mi->p_size = get_dword(buf[31], buf[30], buf[29], buf[28]); ++#undef get_dword ++ ++ mi->a_size = mi->b_off - mi->a_off; ++ mi->a_off += mi->h_off; ++ mi->b_off += mi->h_off; ++ mi->p_off += mi->h_off; ++ ++ mi->width = mi->x2 - mi->x1 + 1; ++ mi->height = mi->y2 - mi->y1 + 1; ++ mi->left_pad = mi->x1 & 07; ++ mi->right_pad = 07 - (mi->x2 & 07); ++ mi->x1 -= mi->left_pad; /* x1 = 8m */ ++ mi->x2 += mi->right_pad; /* x2 = 8n+7 */ ++ mi->p_width = ((mi->x2 + 1) - mi->x1) / (mi->m_256 ? 2 : 4); ++ mi->p_height = (mi->y2 + 1) - mi->y1; ++ ++ if(DEBUG) mag_show_struct(mi); ++} ++ ++static void mag_read_palette(mi, r, g, b) ++ struct mag *mi; ++ byte *r, *g, *b; ++{ ++ int num_palettes; ++ byte *buf; ++ ++ if(mi->m_256) ++ num_palettes = 256; ++ else ++ num_palettes = 16; ++ ++ buf = mag_malloc((size_t)num_palettes * 3, "mag_read_palette"); ++ ++ if(fread(buf, (size_t) 3, (size_t) num_palettes, mi->fp) != num_palettes){ ++ free(buf); ++ mag_file_error(mi, MAG_CORRUPT); ++ } ++ ++ for(num_palettes--; num_palettes >= 0; num_palettes--){ ++ g[num_palettes] = buf[num_palettes * 3 ]; ++ r[num_palettes] = buf[num_palettes * 3 + 1]; ++ b[num_palettes] = buf[num_palettes * 3 + 2]; ++ } ++ ++ free(buf); ++} ++ ++static void mag_read_flags(mi) ++ struct mag *mi; ++{ ++ mi->a = mag_malloc((size_t) mi->a_size, "mag_read_flags#1"); ++ mi->b = mag_malloc((size_t) mi->b_size, "mag_read_flags#2"); ++ ++ fseek(mi->fp, mi->a_off, SEEK_SET); ++ if(fread(mi->a, (size_t) mi->a_size, (size_t) 1, mi->fp) != 1) ++ mag_file_warning(mi, MAG_CORRUPT); ++ if(fread(mi->b, (size_t) mi->b_size, (size_t) 1, mi->fp) != 1) ++ mag_file_warning(mi, MAG_CORRUPT); ++} ++ ++static void mag_read_pixel_data(mi) ++ struct mag *mi; ++{ ++ mi->p = mag_malloc((size_t) mi->p_size, "mag_read_pixel_data"); ++ ++ fseek(mi->fp, mi->p_off, SEEK_SET); ++ if(fread(mi->p, (size_t) mi->p_size, (size_t) 1, mi->fp) != 1) ++ mag_file_warning(mi, MAG_CORRUPT); ++} ++ ++/* MAG expanding routine */ ++static void mag_expand_body(mi, pic0) ++ struct mag *mi; ++ byte **pic0; ++{ ++ int ai, bi, fi, pi; ++ int px, py, x, y; ++ byte *flag; ++ byte mask; ++ data16 *pixel0; ++ ++ flag = mag_malloc((size_t) mi->p_width / 2, "mag_expand_body#1"); ++ *pic0 = mag_malloc((size_t) mi->width * mi->height, "mag_expand_body#2"); // GRR POSSIBLE OVERFLOW / FIXME ++ pixel0 = mag_malloc((size_t) 2 * mi->p_width * 17, "mag_expand_body#3"); // GRR POSSIBLE OVERFLOW / FIXME ++ ++#define pixel(x, y) pixel0[(y) % 17 * mi->p_width + (x)] ++ ++ ai = bi = pi = 0; ++ mask = 0x80; ++ for(y = py = 0; py < mi->p_height; py++){ ++ for(fi = 0; fi < mi->p_width / 2; fi++){ ++ if(py == 0){ ++ if(mi->a[ai] & mask) ++ flag[fi] = mi->b[bi++]; ++ else ++ flag[fi] = 0; ++ }else{ ++ if(mi->a[ai] & mask) ++ flag[fi] ^= mi->b[bi++]; ++ } ++ if((mask >>= 1) == 0){ ++ mask = 0x80; ++ ai++; ++ } ++ } ++ ++ for(px = fi = 0; fi < mi->p_width / 2; fi++){ ++ int f = H4(flag[fi]); ++ if(f == 0){ ++ pixel(px, py) = mi->p[pi] + mi->p[pi + 1] * 256; ++ px++; ++ pi+=2; ++ }else{ ++ int dx = points[f].dx, dy = points[f].dy; ++ pixel(px, py) = pixel(px - dx, py - dy); ++ px++; ++ } ++ ++ f = L4(flag[fi]); ++ if(f == 0){ ++ pixel(px, py) = mi->p[pi] + mi->p[pi + 1] * 256; ++ px++; ++ pi+=2; ++ }else{ ++ int dx = points[f].dx, dy = points[f].dy; ++ pixel(px, py) = pixel(px - dx, py - dy); ++ px++; ++ } ++ } ++ ++#define inside(x) ((unsigned int)(x) < mi->width) ++#define pic(x, y) (*pic0)[(y) * mi->width + (x)] ++ for(x = -mi->left_pad, px = 0; px < mi->p_width; px++){ ++ data16 p = pixel(px, py); ++ if(mi->m_256){ ++ if(inside(x)) ++ pic(x, y) = L8(p); ++ x++; ++ if(inside(x)) ++ pic(x, y) = H8(p); ++ x++; ++ }else{ ++ if(inside(x)) ++ pic(x, y) = H4(L8(p)); ++ x++; ++ if(inside(x)) ++ pic(x, y) = L4(L8(p)); ++ x++; ++ if(inside(x)) ++ pic(x, y) = H4(H8(p)); ++ x++; ++ if(inside(x)) ++ pic(x, y) = L4(H8(p)); ++ x++; ++ } ++ } ++ y++; ++ } ++#undef pic ++#undef inside ++#undef pixel ++ ++ free(flag); ++ free(pixel0); ++} ++ ++ ++/* The main routine to write a MAG file. */ ++int WriteMAG(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle, ++ comment) ++ FILE *fp; ++ byte *pic; ++ int ptype, w, h; ++ byte *rmap, *gmap, *bmap; ++ int numcols, colorstyle; ++ char *comment; ++{ ++ byte rtemp[256], gtemp[256], btemp[256]; ++ struct mag mag; ++ int e; ++ ++ if(DEBUG) fputs("WriteMag\n", stderr); ++ ++ mag_init_info(&mag); ++ mag.fp = fp; ++ ++ if(ptype == PIC24){ ++ if(!(pic = Conv24to8(pic, w, h, 256, rtemp, gtemp, btemp))) ++ mag_memory_error("Conv24to8", "WriteMAG"); ++ rmap = rtemp; ++ gmap = gtemp; ++ bmap = btemp; ++ numcols = 256; ++ mag.m_256 = 1; ++ }else{ ++ if(numcols > 16) ++ mag.m_256 = 1; ++ } ++ ++ if((e = setjmp(mag.jmp)) != 0){ ++ /* When an error occurs, comes here. */ ++ mag_cleanup_mag_info(&mag, 1); ++ return -1; ++ } ++ ++ mag.x2 = w - 1; ++ mag.y2 = h - 1; ++ mag.right_pad = 07 - (mag.x2 & 07); ++ mag.p_width = (w + mag.right_pad) / (mag.m_256 ? 2 : 4); ++ mag.p_height = h; ++ mag.width = w; ++ mag.height = h; ++ mag.a_size = (mag.p_width * mag.p_height + 15) / 16; /* x/2/8 */ // GRR POSSIBLE OVERFLOW / FIXME ++ if(mag.a_size % 2) ++ mag.a_size++; ++ ++ mag_compress_data(&mag, pic); ++ mag_write_check_data(&mag); ++ mag_write_comment(&mag, comment); ++ ++ mag.h_off = ftell(mag.fp); ++ ++ mag_write_palette(&mag, numcols, rmap, gmap, bmap, ++ colorstyle == F_GREYSCALE); ++ mag_write_flags(&mag); ++ mag_write_pixel_data(&mag); ++ mag_write_header(&mag); ++ ++ mag_cleanup_mag_info(&mag, 1); ++ return 0; ++} ++ ++/* MAG compressing routine */ ++static void mag_compress_data(mi, pic0) ++ struct mag *mi; ++ byte *pic0; ++{ ++ int ai, bi, pi, i; ++ int bmax, pmax; ++ byte mask; ++ byte *flag0; ++ data16 *pixel0; ++ int px, py, x, y; ++ ++ pixel0 = mag_malloc((size_t) 2 * mi->p_width * mi->p_height, // GRR POSSIBLE OVERFLOW / FIXME ++ "mag_compress_data#1"); ++ flag0 = mag_malloc((size_t) mi->p_width * mi->p_height, // GRR POSSIBLE OVERFLOW / FIXME ++ "mag_compress_data#2"); ++ ++#define pic(x, y) pic0[(y) * mi->width + (x)] ++ /* convert dots to pixels */ ++ i = 0; ++ for(y = py = 0; py < mi->p_height; py++){ ++ for(x = px = 0; px < mi->p_width; px++){ ++ data16 p = 0; ++ if(mi->m_256){ ++ if(x < mi->width) ++ p += pic(x, y); ++ x++; ++ if(x < mi->width) ++ p += pic(x, y) * 256; ++ x++; ++ }else{ ++ if(x < mi->width) ++ p += pic(x, y) * 16; ++ x++; ++ if(x < mi->width) ++ p += pic(x, y); ++ x++; ++ if(x < mi->width) ++ p += pic(x, y) * 4096; ++ x++; ++ if(x < mi->width) ++ p += pic(x, y) * 256; ++ x++; ++ } ++ pixel0[i++] = p; ++ } ++ y++; ++ } ++#undef pic ++ ++#define pixel(x, y) pixel0[(y) * mi->p_width + (x)] ++#define flag(x, y) flag0[(y) * mi->p_width + (x)] ++ /* get flags */ ++ pmax = pi = 0; ++ for(py = 0; py < mi->p_height; py++){ ++ for(px = 0; px < mi->p_width; px++){ ++ int t; ++ for(t = 0; t < 15; t++){ ++ int dx = points[try[t]].dx, dy = points[try[t]].dy; ++ if(dx <= px && dy <= py){ ++ if(pixel(px - dx, py - dy) == pixel(px, py)) ++ break; ++ } ++ } ++ if(t < 15){ ++ flag(px, py) = try[t]; ++ }else{ ++ flag(px, py) = 0; ++ if(pmax <= pi + 1){ ++ pmax += 128; ++ mi->p = mag_realloc(mi->p, (size_t) pmax, ++ "mag_compress_data#3"); ++ } ++ mi->p[pi++] = L8(pixel(px, py)); ++ mi->p[pi++] = H8(pixel(px, py)); ++ } ++ } ++ } ++#undef flag ++#undef pixel ++ ++ /* pack 2 flags into 1 byte */ ++ for(i = 0; i < mi->p_width / 2 * mi->p_height; i++) ++ flag0[i] = flag0[i * 2] * 16 + flag0[i * 2 + 1]; ++ ++#define flag(x, y) flag0[(y) * mi->p_width / 2 + (x)] ++ for(py = mi->p_height - 1; py >= 1; py--){ ++ for(px = 0; px < mi->p_width / 2; px++) ++ flag(px, py) ^= flag(px, py - 1); ++ } ++#undef flag ++ ++ mask = 0x80; ++ ai = bi = bmax = 0; ++ mi->a = mag_malloc((size_t) mi->a_size, "mag_compress_data#4"); // GRR POSSIBLE OVERFLOW / FIXME ++ for(i = 0; i < mi->p_width / 2 * mi->p_height; i++){ ++ if(flag0[i] == 0){ ++ mi->a[ai] &= ~mask; ++ }else{ ++ if(bmax == bi){ ++ bmax += 128; ++ mi->b = mag_realloc(mi->b, (size_t) bmax, ++ "mag_compress_data#4"); ++ } ++ mi->b[bi++] = flag0[i]; ++ mi->a[ai] |= mask; ++ } ++ ++ if((mask >>= 1) == 0){ ++ mask = 0x80; ++ ai++; ++ } ++ } ++ ++ if(bi % 2) ++ bi++; ++ mi->b_size = bi; ++ ++ mi->p_size = pi; ++ ++ free(pixel0); ++ free(flag0); ++} ++ ++static void mag_write_check_data(mi) ++ struct mag *mi; ++{ ++ if(fwrite(mag_id, (size_t) 8, (size_t) 1, mi->fp) != 1) ++ mag_file_error(mi, MAG_WRITE); ++} ++ ++static void mag_write_comment(mi, comment) ++ struct mag *mi; ++ char *comment; ++{ ++ char *p; ++ int i; ++ ++ if(fputs("XV ", mi->fp) == EOF) ++ mag_file_error(mi, MAG_WRITE); ++ ++ if((p = (char *) getenv("USER")) == NULL) ++ p = "????????"; ++ for(i = 5; i < 24; i++){ ++ if(*p == '\0') ++ break; ++ if(fputc(*p++, mi->fp) == EOF) ++ mag_file_error(mi, MAG_WRITE); ++ } ++ for( ; i < 24; i++){ ++ if(fputc(' ', mi->fp) == EOF) ++ mag_file_error(mi, MAG_WRITE); ++ } ++ ++ if(comment){ ++ int l = strlen(comment); ++ if(l > 0){ ++ int i; ++ for(i = 0; i < l; i++){ ++ if(comment[i] == 0x1a) ++ comment[i] = ' '; ++ } ++ if(fwrite(comment, (size_t) l, (size_t) 1, mi->fp) != 1) ++ mag_file_error(mi, MAG_WRITE); ++ } ++ } ++ ++ if(fputc(0x1a, mi->fp) == EOF) ++ mag_file_error(mi, MAG_WRITE); ++} ++ ++static void mag_write_palette(mi, num, r, g, b, grey) ++ struct mag *mi; ++ int num; ++ byte *r, *g, *b; ++ int grey; ++{ ++ int i, left; ++ char buf[3]; ++ ++ fseek(mi->fp, 32L, SEEK_CUR); /* skip header area */ ++ for(i = 0; i < num; i++){ ++ buf[0] = *g++; ++ buf[1] = *r++; ++ buf[2] = *b++; ++ if(grey) ++ buf[0] = buf[1] = buf[2] = MONO(buf[1], buf[0], buf[2]); ++ if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1) ++ mag_file_error(mi, MAG_WRITE); ++ } ++ if(num < 16){ ++ left = 16 - num; ++ }else if(num == 16){ ++ left = 0; ++ }else if(num < 256){ ++ left = 256 - num; ++ }else if(num == 256){ ++ left = 0; ++ }else ++ left = 0; /* shouldn't happen */ ++ ++ if(left > 0){ ++ for(i = 0; i < left; i++){ ++ if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1) ++ mag_file_error(mi, MAG_WRITE); ++ } ++ } ++} ++ ++static void mag_write_flags(mi) ++ struct mag *mi; ++{ ++ int i; ++ ++ mi->a_off = ftell(mi->fp); ++ for(i = 0; i < mi->a_size; i++){ ++ if(fputc(mi->a[i], mi->fp) == EOF) ++ mag_file_error(mi, MAG_WRITE); ++ } ++ ++ mi->b_off = ftell(mi->fp); ++ for(i = 0; i < mi->b_size; i++){ ++ if(fputc(mi->b[i], mi->fp) == EOF) ++ mag_file_error(mi, MAG_WRITE); ++ } ++} ++ ++static void mag_write_pixel_data(mi) ++ struct mag *mi; ++{ ++ int i; ++ ++ mi->p_off = ftell(mi->fp); ++ for(i = 0; i < mi->p_size; i++){ ++ if(fputc(mi->p[i], mi->fp) == EOF) ++ mag_file_error(mi, MAG_WRITE); ++ } ++} ++ ++static void mag_write_header(mi) ++ struct mag *mi; ++{ ++ byte buf[32]; ++ ++ if(DEBUG) mag_show_struct(mi); ++ ++ mi->a_off -= mi->h_off; ++ mi->b_off -= mi->h_off; ++ mi->p_off -= mi->h_off; ++ ++ buf[ 0] = buf[1] = buf[2] = 0; ++ buf[ 3] = (mi->m_256 ? 0x80 : 0); ++ buf[ 4] = buf[5] = 0; ++ buf[ 6] = buf[7] = 0; ++ buf[ 8] = L8(mi->x2); ++ buf[ 9] = H8(mi->x2); ++ buf[10] = L8(mi->y2); ++ buf[11] = H8(mi->y2); ++ mag_set_double_word(mi->a_off, &buf[12]); ++ mag_set_double_word(mi->b_off, &buf[16]); ++ mag_set_double_word(mi->b_size, &buf[20]); ++ mag_set_double_word(mi->p_off, &buf[24]); ++ mag_set_double_word(mi->p_size, &buf[28]); ++ ++ fseek(mi->fp, mi->h_off, SEEK_SET); ++ if(fwrite(buf, (size_t) 32, (size_t) 1, mi->fp) != 1) ++ mag_file_error(mi, MAG_WRITE); ++} ++ ++static void mag_set_double_word(n, p) ++ long n; ++ byte *p; ++{ ++ p[0] = n % 256; /* ugly...anything wrong with shift/mask operations? */ ++ p[1] = n / 256 % 256; /* (n >> 8) & 0xff */ ++ p[2] = n / 256 / 256 % 256; /* (n >> 16) & 0xff */ ++ p[3] = n / 256 / 256 / 256 % 256; /* (n >> 24) & 0xff */ ++} ++ ++/* ++ * The routines to initialize or clean up. ++ * mag_init_info: ++ * initializes a mag structure. ++ * mag_cleanup_mag_info: ++ * cleans up a mag structure. ++ * mag_cleanup_pinfo: ++ * cleans up a PICINFO structure. ++ */ ++static void mag_init_info(mi) ++ struct mag *mi; ++{ ++ mi->fp = NULL; ++ mi->fsize = 0; ++ mi->m_256 = mi->m_dig = mi->m_8 = mi->m_200 = 0; ++ mi->x1 = mi->y1 = mi->x2 = mi->y2 = 0; ++ mi->left_pad = mi->right_pad = 0; ++ mi->p_width = mi->p_height = mi->width = mi->height = 0; ++ mi->h_off = mi->p_off = mi->p_size = 0; ++ mi->a_off = mi->a_size = mi->b_off = mi->b_size = 0; ++ mi->a = NULL; ++ mi->b = NULL; ++ mi->p = NULL; ++} ++ ++static void mag_cleanup_mag_info(mi, writing) ++ struct mag *mi; ++ int writing; ++{ ++ if(mi->fp && !writing) ++ fclose(mi->fp); ++ if(mi->a) ++ free(mi->a); ++ if(mi->b) ++ free(mi->b); ++ if(mi->p) ++ free(mi->p); ++} ++ ++static void mag_cleanup_pinfo(pinfo) ++ PICINFO *pinfo; ++{ ++ if(pinfo->comment){ ++ free(pinfo->comment); ++ pinfo->comment = NULL; ++ } ++ if(pinfo->pic){ ++ free(pinfo->pic); ++ pinfo->pic = NULL; ++ } ++} ++ ++/* ++ * Error handler. ++ * mag_memory_error: ++ * shows an error message, and terminates. ++ * mag_error: ++ * shows an non-file error message, and jumps to the entry for errors. ++ * mag_file_error: ++ * shows an file error message, and jumps to the entry for errors. ++ * mag_file_warning: ++ * shows an file warning message. ++ */ ++static void mag_memory_error(scm, fn) ++ char *scm, *fn; ++{ ++ char buf[128]; ++ sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn); ++ FatalError(buf); ++} ++ ++static void mag_error(mi, mn) ++ struct mag *mi; ++ int mn; ++{ ++ SetISTR(ISTR_WARNING, "%s", mag_msgs[mn]); ++ longjmp(mi->jmp, 1); ++} ++ ++static void mag_file_error(mi, mn) ++ struct mag *mi; ++ int mn; ++{ ++ if(feof(mi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", mag_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", mag_msgs[mn], ERRSTR(errno)); ++ longjmp(mi->jmp, 1); ++} ++ ++static void mag_file_warning(mi, mn) ++ struct mag *mi; ++ int mn; ++{ ++ if(feof(mi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", mag_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", mag_msgs[mn], ERRSTR(errno)); ++} ++ ++static void mag_show_struct (mi) ++ struct mag *mi; ++{ ++ fprintf(stderr, " 256 colors: %s\n", mi->m_256 ? "true" : "false"); ++ fprintf(stderr, " 8 colors: %s\n", mi->m_8 ? "true" : "false"); ++ fprintf(stderr, " digital colors: %s\n", mi->m_dig ? "true" : "false"); ++ fprintf(stderr, " aspect ratio: %f\n", mi->m_200 ? 0.5 : 1.0); ++ fprintf(stderr, " image size: %dx%d\n", mi->width, mi->height); ++ fprintf(stderr, " left pad: %d\n", mi->left_pad); ++ fprintf(stderr, " right pad: %d\n", mi->right_pad); ++ fprintf(stderr, " h_off: %ld\n", mi->h_off); ++ fprintf(stderr, " A: off:%ld, size:%ld\n", mi->a_off, mi->a_size); ++ fprintf(stderr, " B: off:%ld, size:%ld\n", mi->b_off, mi->b_size); ++ fprintf(stderr, " P: off:%ld, size:%ld\n", mi->p_off, mi->p_size); ++} ++ ++/* Memory related routines. */ ++static void *mag_malloc(n, fn) ++ size_t n; ++ char *fn; ++{ ++ void *r = (void *) malloc(n); ++ if(r == NULL) ++ mag_memory_error("malloc", fn); ++ return r; ++} ++ ++static void *mag_realloc(p, n, fn) ++ void *p; ++ size_t n; ++ char *fn; ++{ ++ void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n); ++ if(r == NULL) ++ mag_memory_error("realloc", fn); ++ return r; ++} ++#endif /* HAVE_MAG */ +diff -ruN xv-3.10a-bugfixes/xvmaki.c xv-3.10a-enhancements/xvmaki.c +--- xv-3.10a-bugfixes/xvmaki.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvmaki.c 2005-04-17 22:57:01.000000000 -0700 +@@ -0,0 +1,794 @@ ++/* ++ * xvmaki.c - load routine for `MAKI' format pictures. ++ * ++ * The `MAKI' format was used by some Japanese personal computer users. ++ */ ++ ++#include "xv.h" ++#include <setjmp.h> ++ ++#ifdef HAVE_MAKI ++ ++typedef unsigned short data16; ++typedef unsigned int data32; ++ ++struct maki_info { ++ jmp_buf jmp; ++ FILE *fp; ++ long fsize; ++ int x0, y0, x1, y1; ++ int width, height; ++ float aspect; ++ long fb_size; ++ long pa_size, pb_size; ++ int m_maki01b, m_200, m_dig8; ++ data16 ext_flag; ++ byte *fa, *fb, *pa, *pb; ++ byte *vs; ++ int numcols; ++ byte *forma, *formb; ++}; ++ ++ ++static void maki_open_file PARM((struct maki_info*, char*)); ++static void maki_check_id PARM((struct maki_info*)); ++static void maki_skip_comment PARM((struct maki_info*)); ++static void maki_read_header PARM((struct maki_info*)); ++static void maki_read_palette PARM((struct maki_info*, ++ byte*, byte*, byte*)); ++static void maki_read_flags PARM((struct maki_info*)); ++static void maki_read_pixel_data PARM((struct maki_info*)); ++static void maki_expand_virtual_screen PARM((struct maki_info*)); ++static void maki_expand_pixel_data PARM((struct maki_info*, byte**)); ++static void maki_init_info PARM((struct maki_info*)); ++ ++static void maki_make_pixel_data PARM((struct maki_info*, byte*)); ++static void maki_make_virtual_screen PARM((struct maki_info*)); ++static void maki_make_flags PARM((struct maki_info*)); ++static void maki_write_check_id PARM((struct maki_info*)); ++static void maki_write_comment PARM((struct maki_info*)); ++static void maki_write_header PARM((struct maki_info*)); ++static void maki_write_palette PARM((struct maki_info*, ++ byte*, byte*, byte*, int)); ++static void maki_write_flags PARM((struct maki_info*)); ++static void maki_write_pixel_data PARM((struct maki_info*)); ++ ++static void maki_cleanup_maki_info PARM((struct maki_info*, int)); ++static void maki_cleanup_pinfo PARM((PICINFO*)); ++static void maki_memory_error PARM((char*, char*)); ++static void maki_error PARM((struct maki_info*, int)); ++static void maki_file_error PARM((struct maki_info*, int)); ++static void maki_file_warning PARM((struct maki_info*, int)); ++static void maki_show_maki_info PARM((struct maki_info*)); ++static void *maki_malloc PARM((size_t, char*)); ++static void *maki_realloc PARM((void *, size_t, char*)); ++ ++static char maki_id_a[] = "MAKI01A "; ++static char maki_id_b[] = "MAKI01B "; ++ ++static char *maki_msgs[] = { ++ NULL, ++#define MAKI_OPEN 1 ++ "can't open file.", ++#define MAKI_CORRUPT 2 ++ "file corrupted.", ++#define MAKI_FORMAT 3 ++ "not MAKI format.", ++#define MAKI_BAD_DATA 4 ++ "bad data.", ++#define MAKI_COMMENT 5 ++ "no '^Z' after comment.", ++#define MAKI_SIZE 6 ++ "bad size.", ++#define MAKI_WRITE 7 ++ "write failed.", ++}; ++ ++#define H4(b) ((b) >> 4 & 0xf) ++#define L4(b) ((b) & 0xf) ++#define error(msg_num) longjmp(mi->jmp, msg_num) ++ ++int LoadMAKI(fname, pinfo) ++ char *fname; ++ PICINFO *pinfo; ++{ ++ struct maki_info maki; ++ int e; ++ ++ if(DEBUG) fputs("LoadMAKI:\n", stderr); ++ ++ pinfo->comment = NULL; ++ maki_init_info(&maki); ++ if((e = setjmp(maki.jmp)) != 0){ ++ /* When an error occurs, comes here. */ ++ maki_cleanup_maki_info(&maki, 0); ++ maki_cleanup_pinfo(pinfo); ++ return 0; ++ } ++ ++ maki_open_file(&maki, fname); ++ maki_check_id(&maki); ++ maki_skip_comment(&maki); ++ maki_read_header(&maki); ++ maki_read_palette(&maki, pinfo->r, pinfo->g, pinfo->b); ++ maki_read_flags(&maki); ++ maki_read_pixel_data(&maki); ++ maki_expand_virtual_screen(&maki); ++ maki_expand_pixel_data(&maki, &pinfo->pic); ++ ++ pinfo->w = pinfo->normw = maki.width; ++ pinfo->h = pinfo->normh = maki.height; ++ pinfo->type = PIC8; ++ pinfo->frmType = F_MAKI; ++ pinfo->colType = F_FULLCOLOR; ++ sprintf(pinfo->fullInfo, "MAKI, 16 colors (%ld bytes)", maki.fsize); ++ sprintf(pinfo->shrtInfo, "%dx%d MAKI", maki.width, maki.height); ++ normaspect = maki.aspect; ++ ++ maki_cleanup_maki_info(&maki, 0); ++ return 1; ++} ++ ++static void maki_open_file(mi, fname) ++ struct maki_info *mi; ++ char *fname; ++{ ++ if((mi->fp = fopen(fname, "rb")) == NULL) ++ maki_file_error(mi, MAKI_OPEN); ++ fseek(mi->fp, (size_t) 0, SEEK_END); ++ mi->fsize = ftell(mi->fp); ++ fseek(mi->fp, (size_t) 0, SEEK_SET); ++} ++ ++static void maki_check_id(mi) ++ struct maki_info *mi; ++{ ++ char buf[8]; ++ if(fread(buf, (size_t) 8, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_CORRUPT); ++ if(strncmp(buf, maki_id_a, (size_t) 8) != 0 && ++ strncmp(buf, maki_id_b, (size_t) 8) != 0) ++ maki_error(mi, MAKI_FORMAT); ++ mi->m_maki01b = (buf[6] == 'B'); ++} ++ ++static void maki_skip_comment(mi) ++ struct maki_info *mi; ++{ ++ int i; ++ int c; ++ ++ for(i = 0; i < 24; i++){ ++ if((c = fgetc(mi->fp)) == EOF) ++ maki_file_error(mi, MAKI_CORRUPT); ++ if(c == '\032') /* ^Z, 0x1a */ ++ break; ++ } ++ if(c != '\032') ++ maki_file_error(mi, MAKI_COMMENT); ++ ++ fseek(mi->fp, 32L, SEEK_SET); ++} ++ ++static void maki_read_header(mi) ++ struct maki_info *mi; ++{ ++ byte buf[16]; ++ ++ if(fread(buf, (size_t) 16, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_CORRUPT); ++ ++ mi->fb_size = (long)buf[ 0] << 8 | (long)buf[ 1]; ++ mi->pa_size = (long)buf[ 2] << 8 | (long)buf[ 3]; ++ mi->pb_size = (long)buf[ 4] << 8 | (long)buf[ 5]; ++ mi->ext_flag = (long)buf[ 6] << 8 | (long)buf[ 7]; ++ mi->x0 = (long)buf[ 8] << 8 | (long)buf[ 9]; ++ mi->y0 = (long)buf[10] << 8 | (long)buf[11]; ++ mi->x1 = (long)buf[12] << 8 | (long)buf[13]; ++ mi->y1 = (long)buf[14] << 8 | (long)buf[15]; ++ ++ mi->width = mi->x1-- - mi->x0; ++ mi->height = mi->y1-- - mi->y0; ++ mi->m_200 = mi->ext_flag & 1; ++ mi->m_dig8 = mi->ext_flag & 2; ++ mi->aspect = mi->m_200 ? 0.5 : 1.0; ++ ++ if(DEBUG) maki_show_maki_info(mi); ++} ++ ++static void maki_read_palette(mi, r, g, b) ++ struct maki_info *mi; ++ byte *r, *g, *b; ++{ ++ byte buf[48], *p; ++ ++ if(fread(buf, (size_t) 48, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_CORRUPT); ++ ++ for(p = buf; p < &buf[48]; ){ ++ *g++ = *p++; ++ *r++ = *p++; ++ *b++ = *p++; ++ } ++} ++ ++static void maki_read_flags(mi) ++ struct maki_info *mi; ++{ ++ mi->fa = maki_malloc((size_t) 1000 , "maki_read_flags#1"); ++ mi->fb = maki_malloc((size_t) mi->fb_size, "maki_read_flags#2"); ++ ++ if(fread(mi->fa, (size_t) 1000, (size_t) 1, mi->fp) != 1) ++ maki_file_warning(mi, MAKI_CORRUPT); ++ if(fread(mi->fb, (size_t) mi->fb_size, (size_t) 1, mi->fp) != 1) ++ maki_file_warning(mi, MAKI_CORRUPT); ++} ++ ++static void maki_read_pixel_data(mi) ++ struct maki_info *mi; ++{ ++ mi->pa = maki_malloc((size_t) mi->pa_size, "maki_read_pixel_data#1"); ++ mi->pb = maki_malloc((size_t) mi->pb_size, "maki_read_pixel_data#2"); ++ ++ if(fread(mi->pa, (size_t) mi->pa_size, (size_t) 1, mi->fp) != 1) ++ maki_file_warning(mi, MAKI_CORRUPT); ++ if(fread(mi->pb, (size_t) mi->pb_size, (size_t) 1, mi->fp) != 1) ++ maki_file_warning(mi, MAKI_CORRUPT); ++} ++ ++static void maki_expand_virtual_screen(mi) ++ struct maki_info *mi; ++{ ++ int x, y, fai, fbi; ++ int bpl = mi->width / 2 / 8; /* bytes per line */ ++ byte mask; ++ mi->vs = maki_malloc((size_t) bpl * mi->height, // GRR POSSIBLE OVERFLOW / FIXME ++ "maki_expand_virtual_screen"); ++ ++ fai = fbi = 0; ++ mask = 0x80; ++ for(y = 0; y < mi->height; y += 4){ ++ for(x = 0; x < mi->width / 2; x += 4){ ++ if(mi->fa[fai] & mask){ ++ byte bh, bl; ++ bh = mi->fb[fbi++]; ++ bl = mi->fb[fbi++]; ++ if(x % 8 == 0){ ++ mi->vs[ y * bpl + x / 8] = H4(bh) << 4; ++ mi->vs[(y + 1) * bpl + x / 8] = L4(bh) << 4; ++ mi->vs[(y + 2) * bpl + x / 8] = H4(bl) << 4; ++ mi->vs[(y + 3) * bpl + x / 8] = L4(bl) << 4; ++ }else{ ++ mi->vs[ y * bpl + x / 8] |= H4(bh); ++ mi->vs[(y + 1) * bpl + x / 8] |= L4(bh); ++ mi->vs[(y + 2) * bpl + x / 8] |= H4(bl); ++ mi->vs[(y + 3) * bpl + x / 8] |= L4(bl); ++ } ++ }else{ ++ if(x % 8 == 0){ ++ mi->vs[ y * bpl + x / 8] = 0; ++ mi->vs[(y + 1) * bpl + x / 8] = 0; ++ mi->vs[(y + 2) * bpl + x / 8] = 0; ++ mi->vs[(y + 3) * bpl + x / 8] = 0; ++ }else{ ++/* mi->vs[ y * bpl + x / 8] |= 0; ++ mi->vs[(y + 1) * bpl + x / 8] |= 0; ++ mi->vs[(y + 2) * bpl + x / 8] |= 0; ++ mi->vs[(y + 3) * bpl + x / 8] |= 0; */ ++ } ++ } ++ ++ if((mask >>= 1) == 0){ ++ mask = 0x80; ++ fai++; ++ } ++ } ++ } ++} ++ ++static void maki_expand_pixel_data(mi, pic) ++ struct maki_info *mi; ++ byte **pic; ++{ ++ int x, y; ++ int vsi, pi, max_pi; ++ byte *p; ++ byte mask; ++ int gap; ++ *pic = maki_malloc((size_t) mi->width * mi->height, // GRR POSSIBLE OVERFLOW / FIXME ++ "maki_expand_pixel_data"); ++ ++ vsi = pi = 0; ++ p = mi->pa; ++ max_pi = mi->pa_size - 1; ++ mask = 0x80; ++ for(y = 0; y < mi->height; y++){ ++ for(x = 0; x < mi->width; x += 2){ ++ if(mi->vs[vsi] & mask){ ++ if(pi > max_pi){ ++ if(p == mi->pb) ++ maki_error(mi, MAKI_BAD_DATA); ++ pi = 0; ++ p = mi->pb; ++ max_pi = mi->pb_size - 1; ++ } ++ (*pic)[y * mi->width + x ] = H4(p[pi]); ++ (*pic)[y * mi->width + x + 1] = L4(p[pi]); ++ pi++; ++ }else{ ++ (*pic)[y * mi->width + x ] = 0; ++ (*pic)[y * mi->width + x + 1] = 0; ++ } ++ ++ if((mask >>= 1) == 0){ ++ mask = 0x80; ++ vsi++; ++ } ++ } ++ } ++ ++ gap = mi->m_maki01b ? 4 : 2; ++ ++ for(y = gap; y < mi->height; y++){ ++ for(x = 0; x < mi->width; x++) ++ (*pic)[y * mi->width + x] ^= (*pic)[(y - gap) * mi->width + x]; ++ } ++} ++ ++ ++int WriteMAKI(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle) ++ FILE *fp; ++ byte *pic; ++ int ptype, w, h; ++ byte *rmap, *gmap, *bmap; ++ int numcols, colorstyle; ++{ ++ byte rtemp[256], gtemp[256], btemp[256]; ++ struct maki_info maki, *mi = &maki; ++ int e; ++ ++ if(DEBUG) fputs("WriteMAKI:\n", stderr); ++ ++ maki_init_info(&maki); ++ if((e = setjmp(maki.jmp)) != 0){ ++ /* An error occurs */ ++ maki_cleanup_maki_info(&maki, 1); ++ return -1; ++ } ++ ++ if(w != 640 || h != 400) { ++ char str[512]; ++ sprintf(str,"MAKI: %s Should be 640x400", maki_msgs[MAKI_SIZE]); ++ ErrPopUp(str, "\nBummer!"); ++ maki_error(mi, MAKI_SIZE); ++ } ++ ++ maki.fp = fp; ++ maki.width = w; ++ maki.height = h; ++ maki.x1 = w - 1; ++ maki.y1 = h - 1; ++ ++ if(ptype == PIC24){ ++ if(!(pic = Conv24to8(pic, w, h, 16, rtemp, gtemp, btemp))) ++ maki_memory_error("Conv24to8#1", "WriteMAKI"); ++ rmap = rtemp; ++ gmap = gtemp; ++ bmap = btemp; ++ }else if(numcols > 16){ ++ if(!(pic = Conv8to24(pic, w, h, rmap, gmap, bmap))) ++ maki_memory_error("Conv8to24", "WriteMAKI"); ++ if(!(pic = Conv24to8(pic, w, h, 16, rtemp, gtemp, btemp))) ++ maki_memory_error("Conv24to8#2", "WriteMAKI"); ++ rmap = rtemp; ++ gmap = gtemp; ++ bmap = btemp; ++ }else ++ maki.numcols = numcols; ++ ++ maki_make_pixel_data(&maki, pic); ++ maki_make_virtual_screen(&maki); ++ maki_make_flags(&maki); ++ maki_write_check_id(&maki); ++ maki_write_comment(&maki); ++ maki_write_header(&maki); ++ maki_write_palette(&maki, rmap, gmap, bmap, colorstyle == F_GREYSCALE); ++ maki_write_flags(&maki); ++ maki_write_pixel_data(&maki); ++ ++ maki_cleanup_maki_info(&maki, 1); ++ return 0; ++} ++ ++static void maki_make_pixel_data(mi, pic) ++ struct maki_info *mi; ++ byte *pic; ++{ ++ int x, y, i; ++ int nza, nzb; ++ ++ mi->forma = maki_malloc((size_t) mi->width / 2 * mi->height, // GRR POSSIBLE OVERFLOW / FIXME ++ "maki_make_pixel_data#1"); ++ mi->formb = maki_malloc((size_t) mi->width / 2 * mi->height, // GRR POSSIBLE OVERFLOW / FIXME ++ "maki_make_pixel_data#2"); ++ ++ for(y = 0; y < mi->height; y++){ ++ for(x = 0; x < mi->width; x += 2){ ++ byte b; ++ b = pic[y * mi->width + x] << 4 | pic[y * mi->width + x + 1]; ++ mi->forma[y * mi->width / 2 + x / 2] = b; ++ mi->formb[y * mi->width / 2 + x / 2] = b; ++ } ++ } ++ ++ for(y = mi->height - 1; y >= 2; y--){ ++ for(x = 0; x < mi->width / 2; x++){ ++ mi->forma[y * mi->width / 2 + x] ^= ++ mi->forma[(y - 2) * mi->width / 2 + x]; ++ } ++ } ++ ++ for(y = mi->height - 1; y >= 4; y--){ ++ for(x = 0; x < mi->width / 2; x++){ ++ mi->formb[y * mi->width / 2 + x] ^= ++ mi->formb[(y - 4) * mi->width / 2 + x]; ++ } ++ } ++ ++ nza = nzb = 0; ++ for(i = 0; i < mi->width / 2 * mi->height; i++){ ++ if(mi->forma[i] != 0) ++ nza++; ++ if(mi->formb[i] != 0) ++ nzb++; ++ } ++ if(nza > nzb){ ++ mi->m_maki01b = 1; ++ free(mi->forma); ++ mi->forma = NULL; ++ }else{ ++ mi->m_maki01b = 0; ++ free(mi->formb); ++ mi->formb = NULL; ++ } ++} ++ ++static void maki_make_virtual_screen(mi) ++ struct maki_info *mi; ++{ ++ int bpl = mi->width / 2 / 8; ++ int vsi, pai, pbi, max_pai, max_pbi; ++ byte mask; ++ byte *pixels; ++ int x, y; ++ ++ mi->vs = maki_malloc((size_t) bpl * mi->height, // GRR POSSIBLE OVERFLOW / FIXME ++ "maki_make_virtual_screen#1"); ++ ++ if(mi->m_maki01b) ++ pixels = mi->formb; ++ else ++ pixels = mi->forma; ++ ++ vsi = pai = pbi = 0; ++ max_pai = max_pbi = -1; ++ mask = 0x80; ++ for(y = 0; y < mi->height; y++){ ++ for(x = 0; x < mi->width / 2; x++){ ++ if(pixels[y * mi->width / 2 + x] == 0){ ++ mi->vs[vsi] &= ~mask; ++ }else{ ++ mi->vs[vsi] |= mask; ++ if(y < 200){ ++ if(pai > max_pai){ ++ max_pai += 1024; ++ mi->pa = maki_realloc(mi->pa, (size_t) max_pai + 1, ++ "maki_make_virtual_screen#2"); ++ } ++ mi->pa[pai++] = pixels[y * mi->width / 2 + x]; ++ }else{ ++ if(pbi > max_pbi){ ++ max_pbi += 1024; ++ mi->pb = maki_realloc(mi->pb, (size_t) max_pbi + 2, ++ "maki_make_virtual_screen#3"); ++ } ++ mi->pb[pbi++] = pixels[y * mi->width / 2 + x]; ++ } ++ } ++ ++ if((mask >>= 1) == 0){ ++ mask = 0x80; ++ vsi++; ++ } ++ } ++ } ++ ++ mi->pa_size = pai; ++ mi->pb_size = pbi; ++} ++ ++static void maki_make_flags(mi) ++ struct maki_info *mi; ++{ ++ int bpl = mi->width / 2 / 8; ++ int fbi, max_fbi; ++ int fai; ++ int x, y; ++ byte mask; ++ ++ mi->fa = maki_malloc((size_t) bpl * mi->height, "maki_make_flags#1"); // GRR POSSIBLE OVERFLOW / FIXME ++ ++ fbi = fai = 0; ++ max_fbi = -1; ++ mask = 0x80; ++ for(y = 0; y < mi->height; y += 4){ ++ for(x = 0; x < mi->width / 2; x += 4){ ++ if(x % 8 == 0){ ++ if(H4(mi->vs[ y * bpl + x / 8]) == 0 && ++ H4(mi->vs[(y + 1) * bpl + x / 8]) == 0 && ++ H4(mi->vs[(y + 2) * bpl + x / 8]) == 0 && ++ H4(mi->vs[(y + 3) * bpl + x / 8]) == 0){ ++ mi->fa[fai] &= ~mask; ++ }else{ ++ mi->fa[fai] |= mask; ++ if(fbi + 1 > max_fbi){ ++ max_fbi += 1024; ++ mi->fb = maki_realloc(mi->fb, (size_t) max_fbi + 1, ++ "maki_make_flags#2"); ++ } ++ mi->fb[fbi++] = H4(mi->vs[ y * bpl + x / 8]) << 4 ++ | H4(mi->vs[(y + 1) * bpl + x / 8]); ++ mi->fb[fbi++] = H4(mi->vs[(y + 2) * bpl + x / 8]) << 4 ++ | H4(mi->vs[(y + 3) * bpl + x / 8]); ++ } ++ }else{ ++ if(L4(mi->vs[ y * bpl + x / 8]) == 0 && ++ L4(mi->vs[(y + 1) * bpl + x / 8]) == 0 && ++ L4(mi->vs[(y + 2) * bpl + x / 8]) == 0 && ++ L4(mi->vs[(y + 3) * bpl + x / 8]) == 0){ ++ mi->fa[fai] &= ~mask; ++ }else{ ++ mi->fa[fai] |= mask; ++ if(fbi + 1 > max_fbi){ ++ max_fbi += 1024; ++ mi->fb = maki_realloc(mi->fb, (size_t) max_fbi + 1, ++ "maki_make_flags#3"); ++ } ++ mi->fb[fbi++] = L4(mi->vs[ y * bpl + x / 8]) << 4 ++ | L4(mi->vs[(y + 1) * bpl + x / 8]); ++ mi->fb[fbi++] = L4(mi->vs[(y + 2) * bpl + x / 8]) << 4 ++ | L4(mi->vs[(y + 3) * bpl + x / 8]); ++ } ++ } ++ ++ if((mask >>= 1) == 0){ ++ mask = 0x80; ++ fai++; ++ } ++ } ++ } ++ ++ mi->fb_size = fbi; ++} ++ ++static void maki_write_check_id(mi) ++ struct maki_info *mi; ++{ ++ char *id = mi->m_maki01b ? maki_id_b : maki_id_a; ++ if(fwrite(id, (size_t) 8, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++} ++ ++static void maki_write_comment(mi) ++ struct maki_info *mi; ++{ ++ char buf[24]; ++ char *p; ++ int i = 0; ++ ++ strcpy(buf, "XV "); ++ ++ if((p = (char *) getenv("USER")) == NULL) ++ p = "????????"; ++ for(i = 5; i < 23; i++){ ++ if(*p == '\0') ++ break; ++ buf[i] = *p++; ++ } ++ for( ; i < 23; i++) ++ buf[i] = ' '; ++ ++ buf[i] = '\032'; /* ^Z, 0x1a */ ++ ++ if(fwrite(buf, (size_t) 24, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++} ++ ++static void maki_write_header(mi) ++ struct maki_info *mi; ++{ ++ byte buf[16]; ++ ++ if(DEBUG) maki_show_maki_info(mi); ++ ++#define set_word(i, v) {buf[i]=(v)>>8&0xff;buf[i+1]=(v)&0xff;} ++ set_word(0, mi->fb_size); ++ set_word(2, mi->pa_size); ++ set_word(4, mi->pb_size); ++ set_word(6, mi->ext_flag); ++ set_word(8, mi->x0); ++ set_word(10, mi->y0); ++ set_word(12, mi->x1 + 1); ++ set_word(14, mi->y1 + 1); ++#undef set_word ++ ++ if(fwrite(buf, (size_t) 16, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++} ++ ++static void maki_write_palette(mi, r, g, b, grey) ++ struct maki_info *mi; ++ byte *r, *g, *b; ++ int grey; ++{ ++ int i; ++ char buf[3]; ++ for(i = 0; i < mi->numcols; i++){ ++ buf[0] = *g++; ++ buf[1] = *r++; ++ buf[2] = *b++; ++ if(grey) ++ buf[0] = buf[1] = buf[2] = MONO(buf[1], buf[0], buf[2]); ++ if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++ } ++ for( ; i < 16; i++){ ++ if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++ } ++} ++ ++static void maki_write_flags(mi) ++ struct maki_info *mi; ++{ ++ int bpl = mi->width / 2 / 8; ++ if(fwrite(mi->fa, (size_t) bpl * mi->height / 16, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++ ++ if(fwrite(mi->fb, (size_t) mi->fb_size, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++} ++ ++static void maki_write_pixel_data(mi) ++ struct maki_info *mi; ++{ ++ if(fwrite(mi->pa, (size_t) mi->pa_size, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++ ++ if(fwrite(mi->pb, (size_t) mi->pb_size, (size_t) 1, mi->fp) != 1) ++ maki_file_error(mi, MAKI_WRITE); ++} ++ ++ ++ ++static void maki_init_info(mi) ++ struct maki_info *mi; ++{ ++ xvbzero((char *)mi, sizeof(struct maki_info)); ++ mi->fp = NULL; ++ mi->fsize = 0; ++ mi->x0 = mi->y0 = mi->x1 = mi->y1 = 0; ++ mi->width = mi->height = 0; ++ mi->aspect = 1.0; ++ mi->fb_size = mi->pa_size = mi->pb_size = 0; ++ mi->m_maki01b = mi->m_200 = mi->m_dig8 = 0; ++ mi->ext_flag = 0; ++ mi->fa = mi->fb = mi->pa = mi->pb = NULL; ++ mi->vs = NULL; ++ mi->numcols = 16; ++ mi->forma = mi->formb = NULL; ++} ++ ++static void maki_cleanup_maki_info(mi, writing) ++ struct maki_info *mi; ++ int writing; ++{ ++ if(mi->fp && !writing) ++ fclose(mi->fp); ++ if(mi->fa) ++ free(mi->fa); ++ if(mi->fb) ++ free(mi->fb); ++ if(mi->pa) ++ free(mi->pa); ++ if(mi->pb) ++ free(mi->pb); ++ if(mi->vs) ++ free(mi->vs); ++ if(mi->forma) ++ free(mi->forma); ++ if(mi->formb) ++ free(mi->formb); ++} ++ ++static void maki_cleanup_pinfo(pi) ++ PICINFO *pi; ++{ ++ if(pi->pic){ ++ free(pi->pic); ++ pi->pic = NULL; ++ } ++} ++ ++static void maki_memory_error(scm, fn) ++ char *scm, *fn; ++{ ++ char buf[128]; ++ sprintf(buf, "%s: coulndn't allocate memory. (%s)", scm, fn); ++ FatalError(buf); ++} ++ ++static void maki_error(mi, mn) ++ struct maki_info *mi; ++ int mn; ++{ ++ SetISTR(ISTR_WARNING, "%s", maki_msgs[mn]); ++ longjmp(mi->jmp, 1); ++} ++ ++static void maki_file_error(mi, mn) ++ struct maki_info *mi; ++ int mn; ++{ ++ if(feof(mi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", maki_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", maki_msgs[mn], ERRSTR(errno)); ++ longjmp(mi->jmp, 1); ++} ++ ++static void maki_file_warning(mi, mn) ++ struct maki_info *mi; ++ int mn; ++{ ++ if(feof(mi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", maki_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", maki_msgs[mn], ERRSTR(errno)); ++} ++ ++static void maki_show_maki_info(mi) ++ struct maki_info *mi; ++{ ++ fprintf(stderr, " file size: %ld.\n", mi->fsize); ++ fprintf(stderr, " image size: %dx%d.\n", mi->width, mi->height); ++ fprintf(stderr, " aspect: %f.\n", mi->aspect); ++ fprintf(stderr, " flag B size: %ld.\n", mi->fb_size); ++ fprintf(stderr, " pixel data size: A:%ld, B:%ld.\n", ++ mi->pa_size, mi->pb_size); ++ fprintf(stderr, " MAKI01B: %s.\n", mi->m_maki01b ? "true" : "false"); ++ fprintf(stderr, " 200 line mode: %s.\n", mi->m_200 ? "true" : "false"); ++ fprintf(stderr, " digital 8 colors: %s.\n", mi->m_dig8 ? "true" : "false"); ++} ++ ++static void *maki_malloc(n, fn) ++ size_t n; ++ char *fn; ++{ ++ void *r = (void *) malloc(n); ++ if(r == NULL) ++ maki_memory_error("malloc", fn); ++ return r; ++} ++ ++static void *maki_realloc(p, n, fn) ++ void *p; ++ size_t n; ++ char *fn; ++{ ++ void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n); ++ if(r == NULL) ++ maki_memory_error("realloc", fn); ++ return r; ++} ++#endif /* HAVE_MAKI */ +diff -ruN xv-3.10a-bugfixes/xvmgcsfx.c xv-3.10a-enhancements/xvmgcsfx.c +--- xv-3.10a-bugfixes/xvmgcsfx.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvmgcsfx.c 2005-05-01 10:20:12.000000000 -0700 +@@ -0,0 +1,2276 @@ ++/* ++ * $Id: xvmgcsfx.c,v 1.23 95/11/27 19:03:36 tin329 Exp Locker: tin329 $ ++ * xvmgcsfx.c - Use the filters as input and output method. ++ * ++ * Features ++ * ======== ++ * Use the filters as input and output method for load and save unsupported ++ * image format file. The filter command is recognized by definition of ++ * magic number or suffix in "~/.xv_mgcsfx" . ++ * ++ * Bugs ++ * ==== ++ * There are many bugs. ++ * Let's go hunting for insects with an insect net. (it's all joke.) ++ * ++ * Author ++ * ====== ++ * Tetsuya INOUE <tin329@chino.it.okayama-u.ac.jp> ++ */ ++ ++/* ++ * Known Bugs and Todo / $B$"$l$3$l5$$K$J$k$3$H(B ++ * ++ * ~/.xv_mgcsfx $BFb(B ++ * $B!&Dj5A$,IT40A4$@$H%(%i!<(B (':'$B$N?t(B)$B!#(B ++ * $B!&%G%j%_%?$H$7$F(B ':' $B$r;H$&$N$G!"%9%?!<%H%"%C%W%U%!%$%kFb$G(B ++ * ':' $B$rMQ$$$FDj5A$O$G$-$J$$!#(B'\:'$B$G$b%@%a!#(B ++ * $B!&(B magic $B%?%$%W$G!"#8?J?t$O#37eJ,#0!A#7$rD4$Y!"#1#6?J?t$O(B ++ * isxdigit $B$,??$rJV$94VCf=hM}$5$l$k!#$7$+$7!"#1#b#y#t#e$H(B ++ * $B$7$F$7$+I>2A$5$l$J$$!#(B ++ * $B!&%W%j%W%m%;%C%5$r;H$&$H$-$O!"%3%a%s%H$N=q$-J}$KCm0U$7$J$1$l$P$J(B ++ * $B$i$J$$!#%W%j%W%m%;%C%5$K$h$C$F$O%3%a%s%H$,%(%i!<$K$J$k!#(B ++ * $B!&%Q%$%W$X$NF~=PNO$N%U%)!<%^%C%H$N<oN`$,(B PNM $B$N$_(B ++ * $BF~NO(B ++ * $B%U%!%$%k%]%$%s%?$r(B seek $B$7$F$O$$$1$J$$(B ++ * $B%U%!%$%k%5%$%:$rMQ$$$F$O$$$1$J$$(B ++ * $B=PNO(B ++ * $B%U%!%$%k%]%$%s%?$r(B seek $B$7$F$O$$$1$J$$(B ++ * exec $B$G$-$J$/$F=*N;$7$?%W%m%;%9$K=q$-9~$_IT2D(B ++ * $B!&%5%U%#%C%/%9$H%^%8%C%/%J%s%P!<$N;H$$J,$1$r$I$&$9$k$+!#(B ++ * $B%^%8%C%/%J%s%P!<$,F1$8$G!"%5%U%#%C%/%9$,0[$J$k>l9g$rG'$a$k$+!)(B ++ * $B!&(Bcompress(gzip)$B$N%U%!%$%k$O%F%s%]%i%j$G$O(B xvtmp??? $B$H$$$&L>A0$J(B ++ * $B$N$G(B suffix $B$G$O<1JL$G$-$J$$!#(B ++ * ++ * $BG'<1$9$k;~$K(B MACBINARY $B$K$OIi$1$k(B(in xv.c)$B!#(B ++ * ++ * $BB?=E$K(B pipe $B$rDL$9$3$H$,$G$-$J$$!#(B(pipe $B$,(B seek $B$G$-$J$$$+$i(B) ++ * $B!&(Bsocketpair $B$G!"(Brecv $B$K(B MSG_PEEK $B%U%i%0$r$D$+$C$F6uFI$_$9$k!#(B ++ * $B!&$3$l$r$d$k$H%U%!%$%k$NG'<1$,$a$A$c$a$A$cCY$/$J$k!#(B ++ * ++ * $B%j%=!<%9$G@_Dj(B ++ * $B!&%j%=!<%9$G@_Dj$9$kJ}$,LLE]$/$5$$(B ++ * ++ * $B%^%8%C%/%J%s%P!<$N@_Dj$K@55,I=8=(B ++ * ++ * $B%;!<%VMQ%W%m%;%9$,<:GT$9$k>l9g$NBP:v$,:#0l$D(B ++ * ++ * DEC OSF/1 V3.0 $B$G$O!"%Q%$%W$K%G!<%?$,$^$@$J$$;~$KFI$_9~$b$&$H$9$k$H!"(B ++ * read $B$,IT40A4$K$J$k!#(B(in xvpbm.c) ++ * $BF1MM$K=q$-9~$_;~$K$bLdBj$,@8$8$k$+$b$7$l$J$$!#(B ++ */ ++ ++#define NEEDSDIR /* for stat() */ ++#include "xv.h" ++ ++ ++#ifdef HAVE_MGCSFX ++ ++ ++#ifdef __osf__ ++# ifdef __alpha ++# define ARCHITECTURE64 1 ++# endif /* __alpha */ ++#endif /* __osf__ */ ++ ++#ifdef ARCHITECTURE64 ++typedef short int16; ++typedef int int32; ++typedef long int64; ++#else ++typedef short int16; ++typedef long int32; ++#endif /* ARCHITECTURE64 */ ++ ++#ifdef sgi ++# define vfork fork ++#endif ++ ++#define USE_SIGCHLD ++#if 0 ++# undef USE_SIGCHLD ++#endif ++ ++#ifdef USE_SIGCHLD ++# include <sys/wait.h> ++#endif ++ ++typedef struct _mgcsfxtab ++{ ++ struct _mgcsfxtab *next; ++ char *description; ++ int mgcsfx_type; ++ int offset; ++ union{ ++ int16 int16_data; ++ int32 int32_data; ++ char *string_data; ++ } dt; ++ int string_len; ++ char *suffix; ++ int input_image_type; ++ char *input_command; ++ int output_image_type; ++ char *output_command; ++} mgcsfxtab; ++ ++ ++#ifndef MGCSFXDIR ++# define MGCSFXDIR "/usr/local/lib" ++#endif ++#ifndef SYSCONFDIR ++# define SYSCONFDIR MGCSFXDIR ++#endif ++#ifndef MGCSFX_SITE_RC ++# define MGCSFX_SITE_RC "xv_mgcsfx" ++#endif ++#ifndef MGCSFX_RC ++# define MGCSFX_RC ".xv_mgcsfx" ++#endif ++ ++#ifdef USE_MGCSFX_PREPROCESSOR ++# ifndef MGCSFX_PREPROCESSOR ++# define MGCSFX_PREPROCESSOR "/usr/lib/cpp" ++# endif ++#endif ++ ++ ++/* Check type for Magic number and Suffix */ ++enum {T_UNKNOWN, ++ T_MAGIC, T_SUFFIX, ++ T_BEINT16, T_BEINT32, T_BEINT64, ++ T_LEINT16, T_LEINT32, T_LEINT64}; ++ ++/* Image Type for input and output format */ ++enum {IT_UNKNOWN, ++#ifdef HAVE_MGCSFX_AUTO ++ IT_AUTO, ++#endif /* HAVE_MGCSFX_AUTO */ ++ IT_PNM, IT_PPM, IT_PGM, IT_PBM, ++ IT_PNM_RAW, IT_PPM_RAW, IT_PGM_RAW, IT_PBM_RAW, ++ IT_PNM_ASCII, IT_PPM_ASCII, IT_PGM_ASCII, IT_PBM_ASCII, ++ IT_GIF, IT_JPEG, IT_TIFF, IT_JFIF, /* IT_PS, IT_COMPRESS,*/ ++ IT_XBM, IT_XPM, IT_BMP, IT_SUNRAS, IT_IRIS, IT_XWD, ++ /* IT_TARGA, IT_FITS, IT_PM, IT_UTAHRLE, IT_PCX, IT_PDSVICAR, IT_IFF, */ ++ IT_MAG, IT_MAKI, IT_PI, IT_PIC, IT_PIC2 /* , IT_PCD */}; ++ ++ ++/*--------------------------------------------------------------------------*/ ++void mgcsfx_handler PARM((int)); ++void mgcsfx_handler_setup PARM((void)); ++ ++#ifdef USE_MGCSFX_PREPROCESSOR ++static char *get_tmp_fname PARM((void)); ++static char *make_preprocessed_file PARM((char *)); ++#endif /* USE_MGCSFX_PREPROCESSOR */ ++ ++int is_mgcsfx PARM((char *, unsigned char *, int)); ++ ++char *mgcsfx_auto_input_com PARM((char *)); ++ ++ ++static mgcsfxtab *free_mgcsfx PARM((mgcsfxtab *)); ++static char *fgettoken PARM((FILE*, int)); ++static int string_fin PARM((char *)); ++static int type_mgcsfx PARM((char *)); ++static int type_image PARM((char *)); ++ ++static void read_mgcsfx PARM((mgcsfxtab **, char *)); ++static void init_mgcsfx PARM((void)); ++static mgcsfxtab *find_mgcsfx PARM((char *, unsigned char *, int)); ++ ++int LoadMGCSFX PARM((char *, PICINFO *)); ++ ++#ifdef SVR4 ++typedef void Sigfunc(int); ++static Sigfunc *xv_signal PARM((int , Sigfunc *)); ++#endif ++ ++/*--------------------------------------------------------------------------*/ ++mgcsfxtab *mgcsfx_table = NULL; ++int mgcsfx_setup_flag = 0; ++ ++int nitem_mgcsfx = 0; ++int desc_width = 0; ++ ++int max_offset_mgcsfx = 0; ++int max_length_mgcsfx = 0; ++int need_buf_size = 0; ++ ++static char input_command_ex[1024]; ++static int input_command_ex_flag = 0; ++ ++#ifdef USE_SIGCHLD ++static int w_p_fail=0; ++#endif ++ ++/*--------------------------------------------------------------------------*/ ++ ++/***************************************************/ ++void mgcsfx_handler(sig) ++ int sig; ++{ ++#ifdef USE_SIGCHLD ++ int pid, pst; ++#endif ++ ++#if defined(SYSV) || defined(SVR4) ++ sighold(sig); ++#else ++ sigblock(sigmask(sig)); ++#endif ++ ++#ifdef USE_SIGCHLD ++ if(w_p_fail == 1){ ++ /* ++ * At this point, process write to broken pipe. ++ * Probably external command was can't exec. ++ */ ++ w_p_fail = 2; ++ pid = wait(&pst); ++ } ++#endif ++ ++ return; ++ ++ /* Quit(1); */ /*exit(1);*/ ++} ++ ++void mgcsfx_handler_setup() ++{ ++#ifdef SVR4 ++ xv_signal(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler); ++ xv_signal(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler); ++#else ++# ifdef SYSV ++ sigset(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler); ++ sigset(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler); ++# else ++ signal(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler); ++ signal(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler); ++# endif ++#endif ++} ++ ++/***************************************************/ ++#ifdef USE_MGCSFX_PREPROCESSOR ++static char *get_tmp_fname() ++{ ++ static char tmp[MAXPATHLEN+1]; ++ ++#ifndef VMS ++ sprintf(tmp, "%s/xvmgcsfxXXXXXX",tmpdir); ++#else ++ /* sprintf(tmp, "Sys$Scratch:xvmgcsfxXXXXXX"); */ ++ strcpy(tmp, "[]xvmgcsfxXXXXXX"); ++#endif /* VMS */ ++ ++#ifdef USE_MKSTEMP ++ close(mkstemp(tmp)); ++#else ++ mktemp(tmp); ++#endif ++ ++ return tmp; ++} ++ ++static char *make_preprocessed_file(fname) ++ char *fname; ++{ ++ char buf[512]; ++ char *tmp_name; ++ ++ tmp_name = get_tmp_fname(); ++ ++#ifndef VMS ++ sprintf(buf,"%s %s > %s", MGCSFX_PREPROCESSOR, fname, tmp_name); ++#else ++ sprintf(buf,"%s %s > %s", MGCSFX_PREPROCESSOR, fname, tmp_name); /* really OK? */ ++#endif ++ ++ SetISTR(ISTR_INFO, "Preprocessing '%s'...", BaseName(fname)); ++#ifndef VMS ++ if (system(buf)) ++#else ++ if (!system(buf)) ++#endif ++ { ++ SetISTR(ISTR_INFO, "Unable to preprocess '%s'.", BaseName(fname)); ++ Warning(); ++ return NULL; ++ } ++ ++ return tmp_name; ++} ++#endif /* USE_MGCSFX_PREPROCESSOR */ ++ ++/***************************************************/ ++/* $BG'<1$G$-$k%U%!%$%k$+$I$&$+D4$Y$k(B */ ++int is_mgcsfx(fname,buffer,size) ++ char *fname; ++ unsigned char *buffer; ++ int size; ++{ ++ mgcsfxtab *magic; ++ FILE *fp; ++ unsigned char *buf; ++ int s; ++ ++ if(nomgcsfx){ ++ return 0; ++ }else{ ++ if(size < need_buf_size){ ++ if((buf = (unsigned char *)calloc(need_buf_size, sizeof(char)))==NULL){ ++ fprintf(stderr,"Can't allocate memory\n"); ++ return 0; ++ } ++ if((fp = xv_fopen(fname, "r"))==NULL){ ++ fprintf(stderr,"Can't open file %s\n", fname); ++ free(buf); ++ return 0; ++ } ++ s = fread(buf, 1, need_buf_size, fp); ++ if((magic = find_mgcsfx(fname, buf, s))!=NULL && ++ magic->input_command != NULL){ ++ free(buf); ++ fclose(fp); ++ return 1; ++ }else{ ++ free(buf); ++ fclose(fp); ++ return 0; ++ } ++ }else{ ++ if((magic = find_mgcsfx(fname, buffer, size))!=NULL && ++ magic->input_command != NULL){ ++ return 1; ++ }else{ ++ return 0; ++ } ++ } ++ } ++} ++ ++#ifdef HAVE_MGCSFX_AUTO ++char *mgcsfx_auto_input_com(fname) ++char *fname; ++{ ++ static char command[1024]; ++ mgcsfxtab *magic; ++ char *ptr; ++ ++ FILE *fp; ++ unsigned char *buf; ++ int s; ++ ++ if((buf = (unsigned char *)calloc(need_buf_size, sizeof(char)))==NULL){ ++ fprintf(stderr,"Can't allocate memory\n"); ++ return NULL; ++ } ++ if((fp = xv_fopen(fname, "r"))==NULL){ ++ fprintf(stderr,"Can't open file %s\n", fname); ++ free(buf); ++ return NULL; ++ } ++ s = fread(buf, 1, need_buf_size, fp); ++ if((magic = find_mgcsfx(fname, buf, s))!=NULL && ++ magic->input_command != NULL && magic->input_image_type == IT_AUTO){ ++ if ((ptr = strstr(magic->input_command, "%s"))){ ++ sprintf(command, magic->input_command, fname); ++ }else{ ++ sprintf(command, "%s < %s", magic->input_command, fname); ++ } ++ free(buf); ++ fclose(fp); ++ return command; ++ }else{ ++ free(buf); ++ fclose(fp); ++ return NULL; ++ } ++} ++#endif /* HAVE_MGCSFX_AUTO */ ++ ++/***************************************************/ ++static mgcsfxtab *free_mgcsfx(m) ++ mgcsfxtab *m; ++{ ++ mgcsfxtab *next; ++ if(m == NULL) return NULL; ++ next = m->next; ++ if(m->description != NULL) free(m->description); ++ if(m->mgcsfx_type == T_MAGIC && m->dt.string_data != NULL) ++ free(m->dt.string_data); ++ if(m->suffix != NULL) free(m->suffix); ++ if(m->input_command != NULL) free(m->input_command); ++ if(m->output_command != NULL) free(m->output_command); ++ free(m); ++ return next; ++} ++ ++ ++ ++/***************************************************/ ++/* char c $B$^$?$O(B '\n' $B$G6h@Z$i$l$?J8;zNs$r<h$j=P$9(B ++ * $B%U%!%$%k$N:G8e$^$GFI$s$@$i(B NULL $B$rJV$9(B ++ * $B2~9T$J$i2~9T$rJV$9(B($B2~9T$G6h@Z$i$l$?>l9g$O(B '\n' $B$r%9%H%j!<%`$KLa$9(B) ++ */ ++#define CBUF_SIZE 1024 ++static char *fgettoken(fp, c) ++ FILE *fp; ++ int c; /* Real mean is char */ ++{ ++ char *buf; ++ char *buf2; ++ int i; ++ int n=0; ++ int max=0; ++ int count = 1; ++ ++ char *ss; ++ char *se; ++ ++ if((buf = (char *)calloc(CBUF_SIZE, sizeof(char))) == NULL){ ++ fprintf(stderr,"Can't allocate memory\n"); ++ exit(1); ++ } ++ max = CBUF_SIZE; ++ count = 2; ++ ++ do{ ++ if((i = getc(fp))==EOF || i == '\n' || i == c) break; ++ ++ buf[n] = (char)i; ++ ++ if(i != c && n == max-1){ ++ buf[max] = '\0'; ++ if((buf2 = (char *)calloc(CBUF_SIZE * count, sizeof(char))) == NULL){ ++ fprintf(stderr,"Can't allocate memory\n"); ++ exit(1); ++ } ++ strcpy(buf2, buf); ++ free(buf); ++ buf = buf2; ++ buf2 = NULL; ++ max = CBUF_SIZE * count; ++ count++; ++ } ++ ++ n++; ++ }while(i != c); ++ ++ buf[n] = '\0'; ++ ++ /* $B:G=i$H:G8e$N6uGrJ8;z$r@Z$j5M$a$k(B */ ++ ss = buf + strspn(buf, " \t\b\r\n"); /* find the first non-white space */ ++ se = buf + strlen(buf); /* find the end of the string */ ++ ++ /* strip from the end first */ ++ while ((--se >= ss) && strchr(" \t\b\r\n", *se)); ++ *(++se) = '\0'; ++ ++ if(i == EOF && strlen(ss)==0){ /* EOF $B$J$i(B NULL $B$rJV$9(B */ ++ free(buf); ++ return NULL; ++ }else if(i == '\n' && strlen(ss)==0){ /* $B2~9T$N$_$N>l9g(B */ ++ static char cr[2] = {'\n','\0'}; ++ buf2 = strdup(cr); ++ free(buf); ++ return buf2; ++ }else{ /* $BDL>o(B */ ++ if(i == '\n' && strlen(ss)>0) ungetc(i,fp); ++ buf2 = strdup(ss); ++ free(buf); ++ return buf2; ++ } ++} ++ ++ ++ ++/***************************************************/ ++/* $BJ8;zNsCf$NFC<l5-9f(B(\)$B$r@5$7$$$b$N$K$9$k(B ++ */ ++static int string_fin(string_data) ++ char *string_data; ++{ ++ char *cptr; ++ char *ptr; ++ int length; ++ ++ /* Change all the \xx sequences into a single character */ ++ cptr = string_data; ++ ++ for (ptr = cptr; *ptr; ++ptr){ ++ if (*ptr != '\\'){ ++ *cptr = *ptr; ++ }else{ ++ switch (*(++ptr)){ ++#if defined(__STDC__) ++ case 'a': /* Audible alert (terminal bell) */ ++ *cptr = '\007'; ++ break; ++ case '?': /* Question mark */ ++ *cptr = '\?'; ++ break; ++#endif ++ case 'b': /* Backspace */ ++ *cptr = '\b'; ++ break; ++ case 'f': /* Form feed */ ++ *cptr = '\f'; ++ break; ++ case 'n': /* Line feed */ ++ *cptr = '\n'; ++ break; ++ case 'r': /* Carriage return */ ++ *cptr = '\r'; ++ break; ++ case 't': /* Horizontal tab */ ++ *cptr = '\t'; ++ break; ++ case 'v': /* Vertical tab */ ++ *cptr = '\v'; ++ break; ++ case '\\': /* Backslash */ ++ *cptr = '\\'; ++ break; ++ case '\'': /* Single quote */ ++ *cptr = '\''; ++ break; ++ case '"': /* Double quote */ ++ *cptr = '\"'; ++ break; ++ case '0': /* Octal constant \0 ... \377 */ ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ if ((ptr[1] >= '0') && (ptr[1] <= '7')){ ++ if ((ptr[2] >= '0') && (ptr[2] <= '7')){ /* \000 ...\377 */ ++ *cptr = ((*ptr - '0') * 64) +((ptr[1] - '0') * 8) +(ptr[1] - '0'); ++ ptr += 2; ++ }else{ /* \00 ...\77 */ ++ *cptr = ((*ptr - '0') * 8) + (ptr[1] - '0'); ++ ++ptr; ++ } ++ }else{ /* \0 ...\7 */ ++ *cptr = *ptr - '0'; ++ } ++ break; ++ case 'x': /* Hexadecimal constant \x0 .. \xff */ ++ if (isxdigit (ptr[1])){ ++ *cptr = 0; ++ while (isxdigit (*(++ptr))) ++ *cptr = (*cptr * 16) + ++ (*ptr > '9' ? tolower (*ptr) - ('a' - 10) : *ptr - '0'); ++ --ptr; ++ break; ++ } ++ default: ++ /* *(cptr++) = '\\'; No use for treat '\z' as 'z' */ ++ *cptr = *ptr; ++ break; ++ } ++ } ++ ++cptr; ++ } ++ *cptr = '\0'; ++ length = cptr - string_data; ++ return length; ++} ++ ++/***************************************************/ ++static int type_mgcsfx(str) ++ char *str; ++{ ++ if(str == NULL){ ++ return T_UNKNOWN; ++ }else if(!strcmp(str, "magic") || !strcmp(str, "MAGIC")){ ++ return T_MAGIC; ++ }else if(!strcmp(str, "string") || !strcmp(str, "STRING")){ ++ return T_MAGIC; ++ }else if(!strcmp(str, "suffix") || !strcmp(str, "SUFFIX")){ ++ return T_SUFFIX; ++ }else if(!strcmp(str, "beint16") || !strcmp(str, "BEINT16")){ ++ return T_BEINT16; ++ }else if(!strcmp(str, "leint16") || !strcmp(str, "LEINT16")){ ++ return T_LEINT16; ++ }else if(!strcmp(str, "beint32") || !strcmp(str, "BEINT32")){ ++ return T_BEINT32; ++ }else if(!strcmp(str, "leint32") || !strcmp(str, "LEINT32")){ ++ return T_LEINT32; ++ }else{ ++ return T_UNKNOWN; ++ } ++} ++ ++/***************************************************/ ++static int type_image(str) ++ char *str; ++{ ++ if(str == NULL){ ++ return IT_UNKNOWN; ++#ifdef HAVE_MGCSFX_AUTO ++ }else if(!strcmp(str, "auto") || !strcmp(str, "AUTO")){ ++ return IT_AUTO; ++#endif /* HAVE_MGCSFX_AUTO */ ++ }else if(!strcmp(str, "pnm") || !strcmp(str, "PNM")){ ++ return IT_PNM; ++ }else if(!strcmp(str, "ppm") || !strcmp(str, "PPM")){ ++ return IT_PPM; ++ }else if(!strcmp(str, "pgm") || !strcmp(str, "PGM")){ ++ return IT_PGM; ++ }else if(!strcmp(str, "pbm") || !strcmp(str, "PBM")){ ++ return IT_PBM; ++ }else if(!strcmp(str, "pnm_raw") || !strcmp(str, "PNM_RAW")){ ++ return IT_PNM_RAW; ++ }else if(!strcmp(str, "ppm_raw") || !strcmp(str, "PPM_RAW")){ ++ return IT_PPM_RAW; ++ }else if(!strcmp(str, "pgm_raw") || !strcmp(str, "PGM_RAW")){ ++ return IT_PGM_RAW; ++ }else if(!strcmp(str, "pbm_raw") || !strcmp(str, "PBM_RAW")){ ++ return IT_PBM_RAW; ++ }else if(!strcmp(str, "pnm_ascii") || !strcmp(str, "PNM_ASCII")){ ++ return IT_PNM_ASCII; ++ }else if(!strcmp(str, "ppm_ascii") || !strcmp(str, "PPM_ASCII")){ ++ return IT_PPM_ASCII; ++ }else if(!strcmp(str, "pgm_ascii") || !strcmp(str, "PGM_ASCII")){ ++ return IT_PGM_ASCII; ++ }else if(!strcmp(str, "pbm_ascii") || !strcmp(str, "PBM_ASCII")){ ++ return IT_PBM_ASCII; ++ ++ }else if(!strcmp(str, "gif") || !strcmp(str, "GIF")){ ++ return IT_GIF; ++ }else if(!strcmp(str, "jpeg") || !strcmp(str, "JPEG")){ ++ return IT_JPEG; ++ }else if(!strcmp(str, "tiff") || !strcmp(str, "TIFF")){ ++ return IT_TIFF; ++ }else if(!strcmp(str, "jfif") || !strcmp(str, "JFIF")){ ++ return IT_JFIF; ++ ++ }else if(!strcmp(str, "xbm") || !strcmp(str, "XBM")){ ++ return IT_XBM; ++ }else if(!strcmp(str, "xpm") || !strcmp(str, "XPM")){ ++ return IT_XPM; ++ }else if(!strcmp(str, "bmp") || !strcmp(str, "BMP")){ ++ return IT_BMP; ++ }else if(!strcmp(str, "sunras") || !strcmp(str, "SUNRAS")){ ++ return IT_SUNRAS; ++ }else if(!strcmp(str, "iris") || !strcmp(str, "IRIS")){ ++ return IT_IRIS; ++ }else if(!strcmp(str, "xwd") || !strcmp(str, "XWD")){ ++ return IT_XWD; ++ ++ }else if(!strcmp(str, "mag") || !strcmp(str, "MAG")){ ++ return IT_MAG; ++ }else if(!strcmp(str, "maki") || !strcmp(str, "MAKI")){ ++ return IT_MAKI; ++ }else if(!strcmp(str, "pi") || !strcmp(str, "PI")){ ++ return IT_PI; ++ }else if(!strcmp(str, "pic") || !strcmp(str, "PIC")){ ++ return IT_PIC; ++ }else if(!strcmp(str, "pic2") || !strcmp(str, "PIC2")){ ++ return IT_PIC2; ++ ++ }else{ ++ return IT_UNKNOWN; ++ } ++} ++ ++/*--------------------------------------------------------------------------*/ ++#define mgcsfx_read_error(FILENAME, LINENUM, AFTERFIELD) \ ++fprintf (stderr,\ ++"%s: line %d: missing fields of %s field\n",\ ++FILENAME, LINENUM, AFTERFIELD); ++ ++#define magic_type_error(FILENAME, LINENUM, MAGICNUMBER) \ ++fprintf (stderr,\ ++"%s: line %d: invalid <magic type> field '%s'\n",\ ++FILENAME, LINENUM, MAGICNUMBER); ++/*--------------------------------------------------------------------------*/ ++ ++/***************************************************/ ++static void read_mgcsfx(mgcsfx_table, fname) ++ mgcsfxtab **mgcsfx_table; ++ char *fname; ++{ ++ FILE *fp; ++ char *s; ++ int line_number = 0; ++ int str_len; ++ int reach_end; ++ int def_err; ++ ++ char *description; ++ char *mgcsfx_type; ++ char *offset; ++ char *magic; ++ char *suffix; ++ char *i_img; ++ char *i_com; ++ char *o_img; ++ char *o_com; ++ ++ mgcsfxtab *ent; ++ mgcsfxtab **entry; ++ ++ ++ if((fp=fopen(fname, "r"))==NULL){ ++ /* fprintf(stderr, "Can't open %s\n",fname); */ ++ return; ++ } ++ ++ while(1){ ++retry: ++ line_number++; ++ def_err = 0; ++ ++ s= NULL; ++ description = mgcsfx_type = offset = magic = suffix ++ = i_img = i_com = o_img = o_com = NULL; ++ reach_end = 0; ++ ++ if((s = fgettoken(fp, ':'))==NULL) break; /* EOF $B$J$i=*$j(B */ ++ if(*s == '#'){/* $B@hF,$,(B '#' $B$J$iFI$_$H$P$9(B */ ++ while((s = fgettoken(fp, '\n'))!=NULL){ ++ if(*s == '\n'){ ++ free(s); ++ goto retry; ++ } ++ free(s); ++ } ++ if(s == NULL) break; ++ }else if(*s == '\n'){/* $B6u9T$OL5;k(B */ ++ free(s); ++ goto retry; ++ } ++ if(strlen(s) > 0) description = s; ++ else free(s); ++ ++ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */ ++ if(s != NULL) free(s); ++ mgcsfx_read_error(fname, line_number, "data type"); ++ goto next; ++ } ++ if(strlen(s) > 0) mgcsfx_type = s; ++ else free(s); ++ ++ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */ ++ if(s != NULL) free(s); ++ mgcsfx_read_error(fname, line_number, "byte offset"); ++ goto next; ++ } ++ if(strlen(s) > 0) offset = s; ++ else free(s); ++ ++ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */ ++ if(s != NULL) free(s); ++ mgcsfx_read_error(fname, line_number, "magic number"); ++ goto next; ++ } ++ if(strlen(s) > 0) magic = s; ++ else free(s); ++ ++ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */ ++ if(s != NULL) free(s); ++ mgcsfx_read_error(fname, line_number, "suffix"); ++ goto next; ++ } ++ if(strlen(s) > 0) suffix = s; ++ else free(s); ++ ++ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */ ++ if(s != NULL) free(s); ++ mgcsfx_read_error(fname, line_number, "input image type"); ++ goto next; ++ } ++ if(strlen(s) > 0) i_img = s; ++ else free(s); ++ ++ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */ ++ if(s != NULL) free(s); ++ mgcsfx_read_error(fname, line_number, "input command"); ++ goto next; ++ } ++ if(strlen(s) > 0) i_com = s; ++ else free(s); ++ ++ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */ ++ if(s != NULL) free(s); ++ mgcsfx_read_error(fname, line_number, "output image type"); ++ goto next; ++ } ++ if(strlen(s) > 0) o_img = s; ++ else free(s); ++ ++ if((s = fgettoken(fp, '#'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */ ++ /* ++ free(s); ++ mgcsfx_read_error(fname, line_number, "output command"); ++ goto next; ++ */ ++ if(s != NULL){ ++ *s = '\0'; ++ reach_end = 1; ++ } ++ } ++ if(s != NULL){ ++ if(strlen(s) > 0) o_com = s; ++ else free(s); ++ } ++ ++ if(reach_end == 0){ ++ while((s = fgettoken(fp, '\n'))!=NULL){/* $B9TKv$N%4%_$r<N$F$k(B */ ++ if(*s == '\n'){ ++ free(s); ++ break; /* goto next; */ ++ } ++ free(s); ++ } ++ }else{ ++ reach_end = 0; ++ } ++ ++ ++ ++ /* --------------------------------------------------------------------- */ ++next:; ++ ++ if(DEBUG){ ++ fprintf(stderr,"Read: file %s: line %d.\n", fname, line_number); ++ fprintf(stderr,"Description : %s\n", ++ description ? description : "-- error --"); ++ fprintf(stderr,"Type : %s\n", ++ mgcsfx_type ? mgcsfx_type : "-- error --"); ++ fprintf(stderr,"Offset : %s\n", offset ? offset : "--+--"); ++ fprintf(stderr,"Magic : %s\n", magic ? magic : "--+--"); ++ fprintf(stderr,"Suffix : %s\n", suffix ? suffix : "--+--"); ++ fprintf(stderr,"i Image : %s\n", i_img ? i_img : "--+--"); ++ fprintf(stderr,"i Command : %s\n", i_com ? i_com : "--+--"); ++ fprintf(stderr,"o Image : %s\n", o_img ? o_img : "--+--"); ++ fprintf(stderr,"o Command : %s\n", o_com ? o_com : "--+--"); ++ fprintf(stderr,"\n"); ++ } ++ ++ /* create mgcsfxtab */ ++ if((ent = (mgcsfxtab *) malloc (sizeof (mgcsfxtab)))==NULL){ ++ fprintf(stderr,"Can't allocate memory\n"); ++ exit(1); ++ } ++ ent->next = NULL; ++ ent->description = NULL; ++ ent->mgcsfx_type = T_UNKNOWN; ++ ent->offset = 0; ++ ent->string_len = 0; ++ ent->suffix = NULL; ++ ent->input_image_type = IT_UNKNOWN; ++ ent->input_command = NULL; ++ ent->output_image_type = IT_UNKNOWN; ++ ent->output_command = NULL; ++ ++ if(description != NULL){ ++ ent->description = description; ++ description = NULL; ++ }else{ ++ fprintf (stderr,"%s: line %d: undefined <description> field.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ } ++ ++ if(mgcsfx_type == NULL){ ++ fprintf (stderr,"%s: line %d: undefined <mgcsfx type> field.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ } ++ ent->mgcsfx_type = type_mgcsfx(mgcsfx_type); ++ switch(ent->mgcsfx_type){ ++ case T_SUFFIX: ++ if(suffix == NULL){ ++ fprintf (stderr, ++ "%s: line %d: conflict definition : undefined <suffix> field.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ } ++ break; ++ case T_BEINT16: ++ if (sscanf(magic, "%hi", &(ent->dt.int16_data)) != 1){ ++ magic_type_error(fname, line_number, magic); ++ def_err ++; ++ goto next2; ++ } ++ break; ++ case T_LEINT16: ++ if (sscanf(magic, "%hi", &(ent->dt.int16_data)) != 1){ ++ magic_type_error(fname, line_number, magic); ++ def_err ++; ++ goto next2; ++ } ++ break; ++#ifdef ARCHITECTURE64 ++ case T_BEINT32: ++ if (sscanf(magic, "%i", &(ent->dt.int32_data)) != 1){ ++ magic_type_error(fname, line_number, magic); ++ def_err ++; ++ goto next2; ++ } ++ break; ++ case T_LEINT32: ++ if (sscanf(magic, "%i", &(ent->dt.int32_data)) != 1){ ++ magic_type_error(fname, line_number, magic); ++ def_err ++; ++ goto next2; ++ } ++ break; ++#else ++ case T_BEINT32: ++ if (sscanf(magic, "%li", &(ent->dt.int32_data)) != 1){ ++ magic_type_error(fname, line_number, magic); ++ def_err ++; ++ goto next2; ++ } ++ break; ++ case T_LEINT32: ++ if (sscanf(magic, "%li", &(ent->dt.int32_data)) != 1){ ++ magic_type_error(fname, line_number, magic); ++ def_err ++; ++ goto next2; ++ } ++ break; ++#endif /* ARCHITECTURE64 */ ++ case T_MAGIC: ++ if(magic == NULL){ ++ fprintf (stderr,"%s: line %d: undefined <magic> field.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ } ++ if((str_len = string_fin(magic))<=0){ ++ fprintf (stderr,"%s: line %d: invalid <magic> field.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ } ++ ++ ent->string_len = str_len; ++ if((ent->dt.string_data = (char *)malloc(str_len + 1))==NULL){ ++ fprintf(stderr,"Can't allocate memory\n"); ++ exit(1); ++ } ++ memcpy(ent->dt.string_data, magic, str_len + 1); ++ break; ++ case T_UNKNOWN: ++ default: ++ fprintf (stderr,"%s: line %d: invalid <mgcsfx type> field.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ break; ++ }; ++ ++ ++ if(offset == NULL){ ++ if(ent->mgcsfx_type == T_MAGIC || ++ ent->mgcsfx_type == T_BEINT16 || ++ ent->mgcsfx_type == T_LEINT16 || ++ ent->mgcsfx_type == T_BEINT32 || ++ ent->mgcsfx_type == T_LEINT32){ ++ fprintf (stderr, ++ "%s: line %d: conflict definition : undefined <offset> field.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ } ++ }else{ ++ if(ent->mgcsfx_type != T_SUFFIX) sscanf(offset, "%i", &(ent->offset)); ++ } ++ ++ if(suffix != NULL){ ++ ent->suffix = suffix; ++ suffix = NULL; ++ } ++ ++ if((i_img == NULL && i_com == NULL) && (o_img == NULL || o_com == NULL)){ ++ fprintf (stderr,"%s: line %d: invalid definition.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ } ++ if((o_img == NULL && o_com == NULL) && (i_img == NULL || i_com == NULL)){ ++ fprintf (stderr,"%s: line %d: invalid definition.\n", ++ fname, line_number); ++ def_err ++; ++ goto next2; ++ } ++ ++ if(i_img != NULL && i_com != NULL){ ++ ent->input_image_type = type_image(i_img); ++ ent->input_command = i_com; ++ i_com = NULL; ++ }else{ ++ ent->input_image_type = IT_UNKNOWN; ++ ent->input_command = NULL; ++ } ++ ++ if(o_img != NULL && o_com != NULL){ ++ ent->output_image_type = type_image(o_img); ++ ent->output_command = o_com; ++ o_com = NULL; ++ }else{ ++ ent->output_image_type = IT_UNKNOWN; ++ ent->output_command = NULL; ++ } ++ /* end of create mgcsfxtab */ ++ ++ ++next2:; ++ ++ if(def_err != 0 || DEBUG){ ++ fprintf(stderr,"Description : %s \t -> %s\n", ++ description ? description : "--+--", ++ ent->description ? ent->description : "-- error --"); ++ fprintf(stderr,"Type : %s \t -> %d\n", ++ mgcsfx_type ? mgcsfx_type : "--+--", ++ ent->mgcsfx_type); ++ fprintf(stderr,"Offset : %s \t -> %d\n", ++ offset ? offset : "--+--", ++ ent->offset); ++ ++ fprintf(stderr,"Magic : %s", magic ? magic : "--+--"); ++ switch(ent->mgcsfx_type){ ++ case T_BEINT16: ++ case T_LEINT16: ++ fprintf(stderr," \t -> %d\n",ent->dt.int16_data); ++ break; ++ case T_BEINT32: ++ case T_LEINT32: ++ fprintf(stderr," \t -> %ld\n",ent->dt.int32_data); ++ break; ++ case T_MAGIC: ++ fprintf(stderr," \t -> %s\n",ent->dt.string_data); ++ break; ++ default: ++ fprintf(stderr,"\n"); ++ break; ++ }; ++ ++ fprintf(stderr,"Suffix : %s \t -> %s\n", ++ suffix ? suffix : "--+--", ++ ent->suffix ? ent->suffix : "--+--"); ++ fprintf(stderr,"i Image : %s \t -> %d\n", ++ i_img ? i_img : "--+--", ++ ent->input_image_type); ++ fprintf(stderr,"i Command : %s \t -> %s\n", ++ i_com ? i_com : "--+--", ++ ent->input_command ? ent->input_command : "--+--"); ++ fprintf(stderr,"o Image : %s \t -> %d\n", ++ o_img ? o_img : "--+--", ++ ent->output_image_type); ++ fprintf(stderr,"o Command : %s \t -> %s\n", ++ o_com ? o_com : "--+--", ++ ent->output_command ? ent->output_command : "--+--"); ++ fprintf(stderr,"\n"); ++ } ++ ++ if(description != NULL) free(description); ++ if(mgcsfx_type != NULL) free(mgcsfx_type); ++ if(offset != NULL) free(offset); ++ if(magic != NULL) free(magic); ++ if(suffix != NULL) free(suffix); ++ if(i_img != NULL) free(i_img); ++ if(i_com != NULL) free(i_com); ++ if(o_img != NULL) free(o_img); ++ if(o_com != NULL) free(o_com); ++ ++ ++ if(def_err != 0) goto next3; ++ ++ /* Override any existing entry for this magic number/file type */ ++ for(entry = mgcsfx_table; *entry; entry = &((*entry)->next)){ ++ if((ent->mgcsfx_type == (*entry)->mgcsfx_type) && ++ ( ++ ((ent->offset == (*entry)->offset) && ++ (((ent->mgcsfx_type == T_BEINT16) && ++ (ent->dt.int16_data == (*entry)->dt.int16_data)) || ++ ((ent->mgcsfx_type == T_BEINT32) && ++ (ent->dt.int32_data == (*entry)->dt.int32_data)) || ++ ((ent->mgcsfx_type == T_LEINT16) && ++ (ent->dt.int16_data == (*entry)->dt.int16_data)) || ++ ((ent->mgcsfx_type == T_LEINT32) && ++ (ent->dt.int32_data == (*entry)->dt.int32_data)) || ++ ++ ((ent->mgcsfx_type == T_MAGIC) && ++ !memcmp(ent->dt.string_data, (*entry)->dt.string_data, ++ ent->string_len)) ++ )) || ++ ((ent->mgcsfx_type == T_SUFFIX) && ++ !strcmp(ent->suffix, (*entry)->suffix)) ++ ) ++ ){ ++ ++ free ((*entry)->description); ++ (*entry)->description = ent->description; ++ ent->description = NULL; ++ ++ (*entry)->input_image_type = ent->input_image_type; ++ if ((*entry)->input_command) free ((*entry)->input_command); ++ (*entry)->input_command = ent->input_command; ++ ent->input_command = NULL; ++ ++ (*entry)->output_image_type = ent->output_image_type; ++ if ((*entry)->output_command) free ((*entry)->output_command); ++ (*entry)->output_command = ent->output_command; ++ ent->output_command = NULL; ++ ++ free_mgcsfx(ent); ++ break; ++ } ++ } ++ if (!*entry){ ++ ent->next = NULL; ++ *entry = ent; ++ } ++ ++ /* if(s == NULL) break; */ ++next3:; ++ if(def_err != 0) free_mgcsfx(ent); ++ } /* end of while(1) */ ++} ++ ++ ++/***************************************************/ ++/* $B%^%8%C%/%J%s%P!<Dj5A%U%!%$%kL>$rF@$F!"FI$_9~$^$;$k(B */ ++static void init_mgcsfx () ++{ ++ extern char *getenv (); ++ ++ char *home_dir; ++ char fname[1024]; ++ mgcsfxtab *entry; ++ int len; ++ struct stat st; ++ ++#ifdef USE_MGCSFX_PREPROCESSOR ++ char *pp_fname; ++#endif /* USE_MGCSFX_PREPROCESSOR */ ++ ++ mgcsfx_table = NULL; ++ ++ mgcsfx_handler_setup(); ++ ++ if(nomgcsfx){ ++ mgcsfx_setup_flag = 1; ++ nitem_mgcsfx = 0; ++ desc_width = 0; ++ }else{ ++ sprintf (fname, "%s/%s", SYSCONFDIR, MGCSFX_SITE_RC); ++ if(stat(fname, &st) == 0 && S_ISREG(st.st_mode)){ ++ /* Read the site MagicSuffix table into a linked list */ ++#ifdef USE_MGCSFX_PREPROCESSOR ++ if((pp_fname = make_preprocessed_file(fname)) != NULL){ ++ read_mgcsfx (&mgcsfx_table, pp_fname); ++ } ++ unlink(pp_fname); ++#else ++ read_mgcsfx (&mgcsfx_table, fname); ++#endif /* USE_MGCSFX_PREPROCESSOR */ ++ } ++ ++ /* Read the personal MgcSfx table into the list overriding site entries */ ++ if ((home_dir = getenv ("HOME"))){ ++ sprintf (fname, "%s/%s", home_dir, MGCSFX_RC); ++ if(stat(fname, &st) == 0 && S_ISREG(st.st_mode)){ ++#ifdef USE_MGCSFX_PREPROCESSOR ++ if((pp_fname = make_preprocessed_file(fname)) != NULL){ ++ read_mgcsfx (&mgcsfx_table, pp_fname); ++ } ++ unlink(pp_fname); ++#else ++ read_mgcsfx (&mgcsfx_table, fname); ++#endif /* USE_MGCSFX_PREPROCESSOR */ ++ } ++ } ++ ++ mgcsfx_setup_flag = 1; ++ ++ nitem_mgcsfx = 0; ++ desc_width = 0; ++ for (entry = mgcsfx_table; entry; entry = entry->next){ ++ nitem_mgcsfx ++; ++ len = strlen(entry->description); ++ if(len > desc_width) desc_width = len; ++ if(max_offset_mgcsfx < entry->offset) max_offset_mgcsfx = entry->offset; ++ if(entry->mgcsfx_type == T_MAGIC && ++ max_length_mgcsfx < entry->string_len) ++ max_length_mgcsfx = entry->string_len; ++ } ++ if(max_length_mgcsfx == 0) max_length_mgcsfx = sizeof(int32); ++ need_buf_size = max_offset_mgcsfx + max_length_mgcsfx + 1;/* 1 is safety */ ++ } ++} ++ ++/***************************************************/ ++/* $B%^%8%C%/%J%s%P!<$rD4$Y$F!"Dj5A$7$F$$$k%F!<%V%k$r8!:w$9$k(B ++ $B%^%8%C%/%J%s%P!<$N%F!<%V%k$rFI$_9~$s$G$$$J$$$J$iFI$_9~$`(B */ ++static mgcsfxtab *find_mgcsfx (fname, buffer, buffer_size) ++ char *fname; ++ unsigned char *buffer; ++ int buffer_size; ++{ ++ mgcsfxtab *entry; ++ int16 buf16; ++ int32 buf32; ++ char *suf; ++ ++ if (mgcsfx_setup_flag == 0) init_mgcsfx (); ++ ++ for (entry = mgcsfx_table; entry; entry = entry->next){ ++ switch (entry->mgcsfx_type){ ++ case T_BEINT16: ++ if ((buffer_size > 0) && ++ ((entry->offset + sizeof (int16)) <= buffer_size)){ ++ buf16 = ((char)*(buffer + entry->offset) << 8) | ++ ((char)*(buffer + entry->offset +1)); ++ if(entry->dt.int16_data == buf16) return entry; ++ } ++ break; ++ case T_LEINT16: ++ if ((buffer_size > 0) && ++ ((entry->offset + sizeof (int16)) <= buffer_size)){ ++ buf16 = ((char)*(buffer + entry->offset +1) << 8) | ++ ((char)*(buffer + entry->offset)); ++ if(entry->dt.int16_data == buf16) return entry; ++ } ++ break; ++ case T_BEINT32: ++ if ((buffer_size > 0) && ++ ((entry->offset + sizeof (int32)) <= buffer_size)){ ++ buf32 = ((char)*(buffer + entry->offset) << 24) | ++ ((char)*(buffer + entry->offset +1) << 16) | ++ ((char)*(buffer + entry->offset +2) << 8) | ++ ((char)*(buffer + entry->offset +3)); ++ if(entry->dt.int32_data == buf32) return entry; ++ } ++ break; ++ case T_LEINT32: ++ if ((buffer_size > 0) && ++ ((entry->offset + sizeof (int32)) <= buffer_size)){ ++ buf32 = ((char)*(buffer + entry->offset +3) << 24) | ++ ((char)*(buffer + entry->offset +2) << 16) | ++ ((char)*(buffer + entry->offset +1) << 8) | ++ ((char)*(buffer + entry->offset)); ++ if(entry->dt.int32_data == buf32) return entry; ++ } ++ break; ++ case T_MAGIC: ++ if ((buffer_size > 0) && ++ ((entry->offset + entry->string_len) ++ <= buffer_size) && ++ !memcmp (entry->dt.string_data, buffer + entry->offset, ++ entry->string_len )) ++ return entry; ++ break; ++ case T_SUFFIX: ++ if(fname != NULL && entry->suffix != NULL){ ++ if(strlen(fname) - strlen(entry->suffix) > 0){ ++ suf = fname + (strlen(fname) - strlen(entry->suffix)); ++ if(!strcmp(suf, entry->suffix)) return entry; ++ } ++ } ++ break; ++ case T_UNKNOWN: ++ default: ++ return NULL; ++ break; ++ } ++ } ++ return NULL; ++} ++ ++ ++ ++ ++ ++/***************************************************/ ++/* $B%^%8%C%/%J%s%P!<$NDj5A$rD4$Y$F!"$=$l$K$"$o$;$?%3%^%s%I$r<B9T$9$k(B */ ++/* if OK return 1, else if ERROR return 0 */ ++int ++LoadMGCSFX(file_name, pinfo) ++ char *file_name; ++ PICINFO *pinfo; ++{ ++ unsigned char *buffer; ++ int size; ++ mgcsfxtab *magic; ++ mgcsfxtab *magic_cur; ++ char *ptr; ++ char command[1024]; ++ int fd[2]; ++ int pid = -2; ++ int file; ++ char *fname; ++ int rv; ++ int pst; ++ ++ int i_it; ++ char *i_com; ++ ++ WaitCursor(); ++ ++ fname = file_name; ++ if((file = open (fname, O_RDONLY))<0){ ++ SetISTR(ISTR_WARNING, "Can't open %s",fname); ++ return 0; ++ } ++ ++ if((buffer = (unsigned char *)calloc(need_buf_size, sizeof(char))) == NULL){ ++ SetISTR(ISTR_WARNING, "Can't allocate memory"); ++ return 0; ++ } ++ ++ magic_cur = NULL; ++ ++/* do{ */ ++ size = read (file, buffer, need_buf_size); ++ ++ if (lseek (file, 0L, 0) < 0){ /* can't seek pipe !! */ ++ fprintf (stderr, "Can't lseek %s\n", file_name); ++ close(file); ++ return 0; ++ } ++ ++ magic = find_mgcsfx (fname, buffer, size); ++ ++ if ((magic != NULL && magic->input_command) || ++ (magic == NULL && mgcsfx && input_command_ex_flag)){ ++ ++ if(magic == NULL){ ++ if (fname != NULL && (ptr = strstr(input_command_ex, "%s"))){ ++ sprintf (command, input_command_ex, fname); ++ }else{ ++ strcpy (command, input_command_ex); ++ fname=NULL; ++ } ++ }else{ ++ /* Use stdin or give file name */ ++ if (fname != NULL && (ptr = strstr(magic->input_command, "%s"))){ ++ sprintf (command, magic->input_command, fname); ++ }else{ ++ strcpy (command, magic->input_command); ++ fname=NULL; ++ } ++ } ++ ++ /* Do the pipe/fork/exec here */ ++ if (pipe (fd) < 0){ ++ fprintf (stderr, "Can't pipe : %s\n", file_name); ++ close(file); ++ return 0; ++ } ++ ++ if ((pid = vfork ()) < 0){ ++ fprintf (stderr, "Can't vfork : %s\n", file_name); ++ close (fd[0]); ++ close (fd[1]); ++ close(file); ++ return 0; ++ } ++ ++ if (!pid){ ++ close(0); ++ if (fname == NULL || (open ("/dev/null", O_RDONLY) < 0)){ ++ dup(file); ++ } ++ close(file); ++ close(1); ++ dup(fd[1]); ++ close(2); ++ open("/dev/null", O_WRONLY); ++ close(fd[0]); ++ execl("/bin/sh", "/bin/sh", "-c", command, 0); ++ _exit(127); ++ } ++ ++ close (fd[1]); ++ dup2(fd[0], file); ++ close (fd[0]); ++ fname = NULL; ++ magic_cur = magic; ++ } ++/* } while(magic != NULL); */ ++ ++ free(buffer); ++ ++ if(magic_cur == NULL && mgcsfx && input_command_ex_flag){ ++ i_it = IT_PNM; ++ i_com = input_command_ex; ++ }else{ ++ i_it = magic_cur->input_image_type; ++ i_com = magic_cur->input_command; ++ } ++ ++ if((magic_cur != NULL && i_com) || ++ (magic_cur == NULL && mgcsfx && input_command_ex_flag)){ ++ switch(i_it){ ++ case IT_PNM: ++ case IT_PPM: ++ case IT_PGM: ++ case IT_PBM: ++ case IT_PNM_RAW: ++ case IT_PPM_RAW: ++ case IT_PGM_RAW: ++ case IT_PBM_RAW: ++ case IT_PNM_ASCII: ++ case IT_PPM_ASCII: ++ case IT_PGM_ASCII: ++ case IT_PBM_ASCII: ++ rv = LoadPBM(file_name, pinfo, file); ++ break; ++ case IT_GIF: ++ case IT_JPEG: ++ case IT_TIFF: ++ case IT_JFIF: ++ case IT_XBM: ++ case IT_XPM: ++ case IT_BMP: ++ case IT_SUNRAS: ++ case IT_IRIS: ++ case IT_XWD: ++ case IT_MAG: ++ case IT_MAKI: ++ case IT_PI: ++ case IT_PIC: ++ case IT_PIC2: ++ SetISTR(ISTR_WARNING, "Yet supported input image type (from filter output)"); ++ rv = 0; ++ break; ++ case IT_UNKNOWN: ++ SetISTR(ISTR_WARNING, "Unknown input image type (from filter output)"); ++ rv = 0; ++ break; ++#ifdef HAVE_MGCSFX_AUTO ++ case IT_AUTO: ++#endif ++ default: ++ SetISTR(ISTR_WARNING, "Error in input image type (from filter output)"); ++ rv = 0; ++ break; ++ } ++ }else{ ++ rv = 0; ++ } ++ ++ /* fail if pid still == -2? */ ++ while(wait(&pst) != pid); /* FIXME? pid isn't necessarily initialized... */ ++ if( *((char *)&pst) != 0 ) rv = 0; ++ ++ input_command_ex_flag = 0; ++ ++ return rv; ++ ++ /* fclose(fp); close in Load??? */ ++ /* return 0; error */ ++ /* return 1; ok */ ++} ++ ++ ++ ++ ++ ++/*--------------------------------------------------------------------------*/ ++#ifndef MGCSFX_DEFAULT_INPUT_COMMAND ++# define MGCSFX_DEFAULT_INPUT_COMMAND "tifftopnm" ++#endif ++#ifndef MGCSFX_DEFAULT_OUTPUT_COMMAND ++# define MGCSFX_DEFAULT_OUTPUT_COMMAND "pnmtotiff" ++#endif ++ ++int MSWIDE = 0; ++int MSHIGH = 0; ++ ++#define MS_NBUTTS 2 ++#define MS_BOK 0 ++#define MS_BCANC 1 ++#define BUTTW 60 /* width of buttons (OK or Cancel) */ ++#define BUTTH 24 /* height of buttons (OK or Cancel) */ ++#define RBSIZE 15 /* width and height of RB button (select, ON or OFF)*/ ++#define CWIDE 8 /* width of character */ ++/* #define CHIGH height of character defined in xv.h */ ++#define MARGIN 3 /* margin of button and label SPACING */ ++ ++#define MSD_TITLE "Save file with external command..." ++#define MSD_RBTITLE "Type of Magic and Suffix" ++#define MSD_IC_TITLE "input command" ++ ++static BUTT msbut[MS_NBUTTS]; ++static RBUTT *typeRB; ++ ++static char output_command_ex[1024]; ++static int output_command_ex_flag = 0; ++ ++static int colorType; ++ ++static int w_pid; ++static int w_pstatus; ++ ++#define MSNAMWIDE 252 /* width of 'file name' entry window */ ++#define MAXFNLEN 256 /* max len of filename being entered */ ++static char DialogFileName[MAXFNLEN+100]; /* filename being entered */ ++static int curPos, stPos, enPos; /* filename textedit stuff */ ++ ++ ++static mgcsfxtab *get_mgcsfx PARM((int)); ++static void changeSuffix PARM((int)); ++ ++static int WriteMGCSFX PARM((FILE**,byte*,int,int,int, ++ byte*,byte*,byte*,int,int,char*, ++ int, int, char*)); ++void CreateMGCSFXW PARM((void)); ++void MGCSFXDialog PARM((int)); ++int MGCSFXCheckEvent PARM((XEvent *)); ++int MGCSFXSaveParams PARM((char *, int)); ++ ++static void drawMSD PARM((int,int,int,int)); ++static void clickMSD PARM((int,int)); ++static void doCmd PARM((int)); ++static int writeMGCSFX PARM((void)); ++ ++static void changeSuffix PARM((int)); ++static void redrawNamMSD PARM((void)); ++static void showFNamMSD PARM((void)); ++static int keyinMSD PARM((int)); ++ ++int getInputCom PARM((void)); ++int getOutputCom PARM((void)); ++/*--------------------------------------------------------------------------*/ ++ ++/***************************************************/ ++/* $B$I$l$rA*$s$@$+D4$Y$k!##0$O%3%^%s%I$rF~NO$9$k$b$N$H$9$k(B */ ++static mgcsfxtab *get_mgcsfx(ms_type) ++ int ms_type; ++{ ++ mgcsfxtab *magic; ++ int i; ++ ++ magic = NULL; ++ if(ms_type != 0){ ++ i = 1; ++ for(magic = mgcsfx_table; (magic && i<ms_type); magic = magic->next){i++;} ++ } ++ return magic; ++} ++ ++/***************************************************/ ++/* $B30It%3%^%s%I$r<B9T$7$F!"$=$l$K=PNO$9$k(B */ ++/* if OK return 0, else if ERROR return -1 */ ++static ++int WriteMGCSFX(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,file_name, ++ ms_type, file, comment) ++ FILE **fp; ++ byte *pic; ++ int ptype, w,h; ++ byte *rmap, *gmap, *bmap; ++ int numcols, colorstyle; ++ char *file_name; ++ int ms_type; ++ int file; /* file descriptor */ ++ char *comment; ++{ ++ mgcsfxtab *magic; ++ ++ int fd[2]; ++ int pid; ++ int rv; ++ ++ WaitCursor(); ++ ++#ifdef USE_SIGCHLD ++ w_p_fail = 1; ++#endif ++ ++ magic = get_mgcsfx(ms_type); ++ if(ms_type != 0 && magic == NULL) return -1; ++ ++ if ((ms_type == 0 && output_command_ex_flag) || ++ (ms_type !=0 && magic != NULL && magic->output_command)){ ++ ++ /* Do the pipe/fork/exec here */ ++ if (pipe (fd) < 0){ ++ fprintf (stderr, "Can't pipe : %s\n", file_name); ++ return -1; ++ } ++ ++ if ((pid = vfork ()) < 0){ ++ fprintf (stderr, "Can't vfork : %s\n", file_name); ++ close (fd[0]); ++ close (fd[1]); ++ return -1; ++ } ++ ++ if (!pid){ ++ close(1); ++ dup(file); ++ close(file); ++ close(0); ++ dup(fd[0]); ++ close(2); ++ open("/dev/null", O_WRONLY); ++ close(fd[1]); ++ if(ms_type == 0){ ++ execl("/bin/sh", "/bin/sh", "-c", output_command_ex, 0); ++ }else{ ++ execl("/bin/sh", "/bin/sh", "-c", magic->output_command, 0); ++ } ++ _exit(127); ++ } ++ ++ close (fd[0]); ++ dup2(fd[1], file); ++ close (fd[1]); ++ ++ }else{ ++ return -1; ++ } ++ ++ ++ *fp = fdopen(file, "w"); ++ ++ /* sleep(1); Best way is wait for checking SIGCHLD, but it's feel waist.*/ ++ ++#ifdef USE_SIGCHLD ++ if(w_p_fail != 2){ ++#endif ++ if(ms_type == 0){ ++ rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle, ++ 1, comment); ++ }else{ ++ switch(magic -> output_image_type){ ++ case IT_PNM: ++ case IT_PPM: ++ case IT_PGM: ++ case IT_PBM: ++ case IT_PNM_RAW: ++ case IT_PPM_RAW: ++ case IT_PGM_RAW: ++ case IT_PBM_RAW: ++ rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle, ++ 1, comment); ++ break; ++ case IT_PNM_ASCII: ++ case IT_PPM_ASCII: ++ case IT_PGM_ASCII: ++ case IT_PBM_ASCII: ++ rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle, ++ 0, comment); ++ break; ++ case IT_GIF: ++ case IT_JPEG: ++ case IT_TIFF: ++ case IT_JFIF: ++ case IT_XBM: ++ case IT_XPM: ++ case IT_BMP: ++ case IT_SUNRAS: ++ case IT_IRIS: ++ case IT_XWD: ++ case IT_MAG: ++ case IT_MAKI: ++ case IT_PI: ++ case IT_PIC: ++ case IT_PIC2: ++ SetISTR(ISTR_WARNING, "Yet supported output image type (to filter input)"); ++ rv = -1; ++ break; ++ case IT_UNKNOWN: ++ SetISTR(ISTR_WARNING, "Unknown output image type (to filter input)"); ++ rv = -1; ++ break; ++#ifdef HAVE_MGCSFX_AUTO ++ case IT_AUTO: ++#endif ++ default: ++ SetISTR(ISTR_WARNING, "Error in output image type (to filter input)"); ++ rv = -1; ++ break; ++ } ++ } ++#ifdef USE_SIGCHLD ++ }else{ ++ rv = -1; ++ } ++#endif ++ ++#ifdef USE_SIGCHLD ++ if(w_p_fail != 2){ ++#endif ++ w_pid = pid; ++#ifdef USE_SIGCHLD ++ w_p_fail = 0; ++ }else{ ++ rv = -1; ++ } ++#endif ++ ++ output_command_ex_flag = 0; ++ ++ return rv; ++ ++ /* fclose(*fp); close in CloseOutFile in writeMGCSFX */ ++ /* return 0; ok */ ++ /* return -1; error */ ++} ++ ++/***************************************************/ ++void CreateMGCSFXW() ++{ ++ int y; ++ int type_num; ++ mgcsfxtab *entry; ++ ++ if (mgcsfx_setup_flag == 0) init_mgcsfx (); ++ ++ if(desc_width < strlen(MSD_IC_TITLE)) desc_width = strlen(MSD_IC_TITLE); ++ nitem_mgcsfx ++; ++ ++ MSWIDE = desc_width * CWIDE + RBSIZE + 36; /* 36 is start of RB button */ ++ MSHIGH = nitem_mgcsfx * (RBSIZE + MARGIN); ++ ++ if(MSWIDE < strlen(MSD_TITLE) + 20) MSWIDE = strlen(MSD_TITLE) + 20; ++ if(MSWIDE < strlen(MSD_RBTITLE) + 16) MSWIDE = strlen(MSD_RBTITLE) + 16; ++ if(MSWIDE < MSNAMWIDE + 10) MSWIDE = MSNAMWIDE + 10; ++ if(MSWIDE < BUTTW * 2 + 10) MSWIDE = BUTTW * 2 + 10; ++ ++ MSHIGH += 55 + LINEHIGH + 10 + BUTTH + 10; ++ ++ MSWIDE += 20; /* right side margin */ ++ MSHIGH += 10; /* RB buttun down side margin */ ++ ++ ++ mgcsfxW = CreateWindow("xv mgcsfx", "XVmgcsfx", NULL, ++ MSWIDE, MSHIGH, infofg, infobg, 0); ++ if (!mgcsfxW) FatalError("can't create mgcsfx window!"); ++ ++ XSelectInput(theDisp, mgcsfxW, ++ ExposureMask | ButtonPressMask | KeyPressMask); ++ ++ mgcsfxNameW = XCreateSimpleWindow(theDisp, mgcsfxW, ++ 10, MSHIGH-LINEHIGH-10-BUTTH-10-1, ++ (u_int) MSNAMWIDE+6, (u_int) LINEHIGH+5, ++ 1, infofg, infobg); ++ if (!mgcsfxNameW) FatalError("can't create mgcsfx name window"); ++ XSelectInput(theDisp, mgcsfxNameW, ExposureMask); ++ ++ /* Ok $B%\%?%s(B */ ++ BTCreate(&msbut[MS_BOK], mgcsfxW, ++ MSWIDE-BUTTW-10-BUTTW-10-1, MSHIGH-BUTTH-10-1, ++ BUTTW, BUTTH, ++ "Ok", infofg, infobg, hicol, locol); ++ /* Cancel $B%\%?%s(B*/ ++ BTCreate(&msbut[MS_BCANC], mgcsfxW, ++ MSWIDE-BUTTW-10-1, MSHIGH-BUTTH-10-1, ++ BUTTW, BUTTH, ++ "Cancel", infofg, infobg, hicol, locol); ++ ++ y = 55; ++ /* User should input command to exec external command */ ++ typeRB = RBCreate(NULL, mgcsfxW, 36, y, MSD_IC_TITLE, ++ infofg, infobg,hicol,locol); ++ y += (RBSIZE + MARGIN); /* 18 */ ++ ++ type_num = 1; ++ for (entry = mgcsfx_table; entry; entry = entry->next){ ++ RBCreate(typeRB, mgcsfxW, 36, y, entry->description, ++ infofg, infobg,hicol,locol); ++ y += (RBSIZE + MARGIN); /* 18 */ ++ if(entry->output_command == NULL){ ++ RBSetActive(typeRB, type_num, 0); /* if no command, off */ ++ } ++ type_num++; ++ } ++ ++ XMapSubwindows(theDisp, mgcsfxW); ++} ++ ++ ++/***************************************************/ ++void MGCSFXDialog(vis) ++ int vis; ++{ ++ if (vis) { ++ CenterMapWindow(mgcsfxW, msbut[MS_BOK].x + msbut[MS_BOK].w/2, ++ msbut[MS_BOK].y + msbut[MS_BOK].h/2, MSWIDE, MSHIGH); ++ } ++ else XUnmapWindow(theDisp, mgcsfxW); ++ mgcsfxUp = vis; ++} ++ ++ ++/***************************************************/ ++int MGCSFXCheckEvent(xev) ++ XEvent *xev; ++{ ++ /* check event to see if it's for one of our subwindows. If it is, ++ deal accordingly, and return '1'. Otherwise, return '0' */ ++ ++ int rv; ++ rv = 1; ++ ++ if (!mgcsfxUp) return (0); ++ ++ if (xev->type == Expose) { ++ int x,y,w,h; ++ XExposeEvent *e = (XExposeEvent *) xev; ++ x = e->x; y = e->y; w = e->width; h = e->height; ++ ++ if (e->window == mgcsfxW) drawMSD(x, y, w, h); ++ else rv = 0; ++ } ++ ++ else if (xev->type == ButtonPress) { ++ XButtonEvent *e = (XButtonEvent *) xev; ++ int x,y; ++ x = e->x; y = e->y; ++ ++ if (e->button == Button1) { ++ if (e->window == mgcsfxW) clickMSD(x,y); ++ else rv = 0; ++ } /* button1 */ ++ else rv = 0; ++ } /* button press */ ++ ++ else if (xev->type == KeyPress) { ++ XKeyEvent *e = (XKeyEvent *) xev; ++ char buf[128]; KeySym ks; XComposeStatus status; ++ int stlen; ++ ++ stlen = XLookupString(e,buf,128,&ks,&status); ++ buf[stlen] = '\0'; ++ ++ if (e->window == mgcsfxW) { ++ if (stlen) { ++ keyinMSD(buf[0]); ++ } ++ } ++ else rv = 0; ++ } ++ else rv = 0; ++ ++ if (rv == 0 && (xev->type == ButtonPress || xev->type == KeyPress)) { ++ XBell(theDisp, 50); ++ rv = 1; /* eat it */ ++ } ++ ++ return (rv); ++} ++ ++ ++/***************************************************/ ++int MGCSFXSaveParams(fname, col) ++ char *fname; ++ int col; ++{ ++ colorType = col; ++ strcpy(DialogFileName, GetDirFName()); ++ return (0); ++} ++ ++/***************************************************/ ++/* $B%@%$%"%m%0$rI=<($9$k$H$-$N=hM}(B */ ++static void drawMSD(x,y,w,h) ++ int x,y,w,h; ++{ ++ int i; ++ XRectangle xr; ++ ++ xr.x = x; xr.y = y; xr.width = w; xr.height = h; ++ XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted); ++ ++ XSetForeground(theDisp, theGC, infofg); ++ XSetBackground(theDisp, theGC, infobg); ++ ++ for (i = 0; i < MS_NBUTTS; i++) BTRedraw(&msbut[i]); ++ ++ ULineString(mgcsfxW, typeRB->x-16, typeRB->y-3-DESCENT, ++ MSD_RBTITLE); ++ RBRedraw(typeRB, -1); ++ ++ DrawString(mgcsfxW, 20, 29, MSD_TITLE); ++ ++ XSetClipMask(theDisp, theGC, None); ++ ++ showFNamMSD(); ++} ++ ++/***************************************************/ ++/* $B%@%$%"%m%0$r%/%j%C%/$7$?$H$-$N=hM}(B */ ++static void clickMSD(x,y) ++ int x,y; ++{ ++ int i; ++ BUTT *bp; ++ ++ /* check BUTTs */ ++ ++ /* check the RBUTTS first, since they don't DO anything */ ++ if ((i = RBClick(typeRB, x,y)) >= 0) { /* $BA*Br(B(type)$B%\%?%s$N=hM}(B */ ++ (void) RBTrack(typeRB, i); /* $BA*Br(B(type)$B%\%?%s$r2!$7$?$H$-(B */ ++ changeSuffix(i); ++ return; ++ } ++ ++ for (i = 0; i < MS_NBUTTS; i++) { /* Ok,Cancel $B%\%?%s$N=hM}(B */ ++ bp = &msbut[i]; ++ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) ++ break; ++ } ++ if (i < MS_NBUTTS) /* found one */ /* Ok,Cancel $B%\%?%s$r2!$7$?$H$-(B */ ++ if (BTTrack(bp)) doCmd(i); ++} ++ ++/***************************************************/ ++/* $B%\%?%s(B(Ok, Cancel) $B$N=hM}(B */ ++static void doCmd(cmd) ++ int cmd; ++{ ++ int rv; ++ ++ switch (cmd) { ++ case MS_BOK: /* Ok button */ { ++ char *fullname; ++ ++ rv = writeMGCSFX(); /* Save with filter(MGCSFX) */ ++ MGCSFXDialog(0); ++ ++ fullname = GetDirFullName(); ++ if (!ISPIPE(fullname[0])) { ++ XVCreatedFile(fullname); ++ if(!rv) StickInCtrlList(0); ++ } ++ } ++ break; ++ case MS_BCANC: /* Cancel button */ ++ DialogFileName[0] = '\0'; ++ curPos = stPos = enPos = 0; ++ MGCSFXDialog(0); ++ break; ++ default: ++ break; ++ } ++} ++ ++/*******************************************/ ++static int writeMGCSFX() ++{ ++ int rv, type; ++ int ptype, w, h, pfree, nc; ++ byte *inpix, *rmap, *gmap, *bmap; ++ ++ FILE *fp = NULL; ++ int file; ++ char *fullname; ++ ++ rv = -1; ++ type = RBWhich(typeRB); ++ ++ SetDirFName(DialogFileName); /* change filename in dir dialog */ ++ fullname = GetDirFullName(); ++ ++ if(type == 0){ ++ if(getOutputCom() == 0) return rv; ++ } ++ ++ file = OpenOutFileDesc(fullname); ++ if(file < 0) return rv; ++ ++ WaitCursor(); ++ inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap); ++ ++ rv = WriteMGCSFX(&fp, inpix, ptype, w, h, ++ rmap, gmap, bmap, nc, colorType, fullname, ++ type, file, picComments); ++ ++ SetCursors(-1); ++ ++ if (CloseOutFile(fp, fullname, rv) == 0) DirBox(0); ++ ++ WaitCursor(); ++#ifdef USE_SIGCHLD ++ if(w_p_fail == 0){ ++#endif ++ while(wait(&w_pstatus) != w_pid); /* if( *((char *)&w_pstatus) != 0 ) ; */ ++#ifdef USE_SIGCHLD ++ }else{ ++ w_p_fail = 0; ++ } ++#endif ++ w_pid = 0; ++ w_pstatus = 0; ++ ++ if (pfree) free(inpix); ++ return rv; ++} ++ ++ ++/***************************************/ ++static void changeSuffix(ms_type) ++ int ms_type; ++{ ++ /* see if there's a common suffix at the end of the DialogFileName. ++ if there is, remember what case it was (all caps or all lower), lop ++ it off, and replace it with a new appropriate suffix, in the ++ same case */ ++ ++ int allcaps; ++ char *suffix, *sp, *dp, lowsuf[512]; ++ mgcsfxtab *magic; ++ ++ /* find the last '.' in the DialogFileName */ ++ suffix = (char *) rindex(DialogFileName, '.'); ++ if (!suffix) return; ++ suffix++; /* point to first letter of the suffix */ ++ ++ /* check for all-caposity */ ++ for (sp = suffix, allcaps=1; *sp; sp++) ++ if (islower(*sp)) allcaps = 0; ++ ++ /* copy the suffix into an all-lower-case buffer */ ++ for (sp=suffix, dp=lowsuf; *sp; sp++, dp++) { ++ *dp = (isupper(*sp)) ? tolower(*sp) : *sp; ++ } ++ *dp = '\0'; ++ ++ ++ magic = get_mgcsfx(ms_type); ++ if(magic != NULL && magic->suffix != NULL){ ++ strcpy(lowsuf,(magic->suffix)+1); ++ ++ if (allcaps) { /* upper-caseify lowsuf */ ++ for (sp=lowsuf; *sp; sp++) ++ *sp = (islower(*sp)) ? toupper(*sp) : *sp; ++ } ++ ++ /* one other case: if the original suffix started with a single ++ capital letter, make the new suffix start with a single cap */ ++ if (isupper(suffix[0])) lowsuf[0] = toupper(lowsuf[0]); ++ ++ strcpy(suffix, lowsuf); /* tack onto DialogFileName */ ++ showFNamMSD(); ++ } ++} ++ ++/***************************************************/ ++/* $B%@%$%"%m%0Fb$K%U%!%$%k%M!<%`$rI=<($9$k$H$-$N=hM}(B ($B2<@A$1(B)*/ ++static void redrawNamMSD() ++{ ++ int cpos; ++ ++ /* draw substring DialogFileName[stPos:enPos] and cursor */ ++ ++ Draw3dRect(mgcsfxNameW, 0, 0, (u_int) MSNAMWIDE+5, (u_int) LINEHIGH+4, R3D_IN, 2, ++ hicol, locol, infobg); ++ ++ XSetForeground(theDisp, theGC, infofg); ++ ++ if (stPos>0) { /* draw a "there's more over here" doowah */ ++ XDrawLine(theDisp, mgcsfxNameW, theGC, 0,0,0,LINEHIGH+5); ++ XDrawLine(theDisp, mgcsfxNameW, theGC, 1,0,1,LINEHIGH+5); ++ XDrawLine(theDisp, mgcsfxNameW, theGC, 2,0,2,LINEHIGH+5); ++ } ++ ++ if ((size_t) enPos < strlen(DialogFileName)) { ++ /* draw a "there's more over here" doowah */ ++ XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+5,0,MSNAMWIDE+5,LINEHIGH+5); ++ XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+4,0,MSNAMWIDE+4,LINEHIGH+5); ++ XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+3,0,MSNAMWIDE+3,LINEHIGH+5); ++ } ++ ++ XDrawString(theDisp, mgcsfxNameW, theGC,3,ASCENT+3,DialogFileName+stPos, enPos-stPos); ++ ++ cpos = XTextWidth(mfinfo, &DialogFileName[stPos], curPos-stPos); ++ XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2, 3+cpos, 2+CHIGH+1); ++ XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2+CHIGH+1, 5+cpos, 2+CHIGH+3); ++ XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2+CHIGH+1, 1+cpos, 2+CHIGH+3); ++} ++ ++/***************************************************/ ++/* $B%@%$%"%m%0Fb$K%U%!%$%k%M!<%`$rI=<($9$k(B */ ++static void showFNamMSD() ++{ ++ int len; ++ ++ len = strlen(DialogFileName); ++ ++ if (curPos<stPos) stPos = curPos; ++ if (curPos>enPos) enPos = curPos; ++ ++ if (stPos>len) stPos = (len>0) ? len-1 : 0; ++ if (enPos>len) enPos = (len>0) ? len-1 : 0; ++ ++ /* while substring is shorter than window, inc enPos */ ++ ++ while (XTextWidth(mfinfo, &DialogFileName[stPos], enPos-stPos) < MSNAMWIDE ++ && enPos<len) { enPos++; } ++ ++ /* while substring is longer than window, dec enpos, unless enpos==curpos, ++ in which case, inc stpos */ ++ ++ while (XTextWidth(mfinfo, &DialogFileName[stPos], enPos-stPos) > MSNAMWIDE) { ++ if (enPos != curPos) enPos--; ++ else stPos++; ++ } ++ ++ ++ if (ctrlColor) XClearArea(theDisp, mgcsfxNameW, 2,2, (u_int) MSNAMWIDE+5-3, ++ (u_int) LINEHIGH+4-3, False); ++ else XClearWindow(theDisp, mgcsfxNameW); ++ ++ redrawNamMSD(); ++ BTSetActive(&msbut[MS_BOK], strlen(DialogFileName)!=0); ++} ++ ++/***************************************************/ ++/* $B%-!<F~NO$7$?$H$-$N=hM}(B */ ++static int keyinMSD(c) ++ int c; ++{ ++ /* got keypress in dirW. stick on end of DialogFileName */ ++ int len; ++ ++ len = strlen(DialogFileName); ++ ++ if (c>=' ' && c<'\177') { /* printable characters */ ++ /* note: only allow 'piped commands' in savemode... */ ++ ++ /* only allow spaces in 'piped commands', not filenames */ ++ if (c==' ' && (!ISPIPE(DialogFileName[0]) || curPos==0)) return (-1); ++ ++ /* only allow vertbars in 'piped commands', not filenames */ ++ if (c=='|' && curPos!=0 && !ISPIPE(DialogFileName[0])) return(-1); ++ ++ if (len >= MAXFNLEN-1) return(-1); /* max length of string */ ++ xvbcopy(&DialogFileName[curPos], &DialogFileName[curPos+1], (size_t) (len-curPos+1)); ++ DialogFileName[curPos]=c; curPos++; ++ } ++ ++ else if (c=='\010' || c=='\177') { /* BS or DEL */ ++ if (curPos==0) return(-1); /* at beginning of str */ ++ xvbcopy(&DialogFileName[curPos], &DialogFileName[curPos-1], (size_t) (len-curPos+1)); ++ curPos--; ++ } ++ ++ else if (c=='\025') { /* ^U: clear entire line */ ++ DialogFileName[0] = '\0'; ++ curPos = 0; ++ } ++ ++ else if (c=='\013') { /* ^K: clear to end of line */ ++ DialogFileName[curPos] = '\0'; ++ } ++ ++ else if (c=='\001') { /* ^A: move to beginning */ ++ curPos = 0; ++ } ++ ++ else if (c=='\005') { /* ^E: move to end */ ++ curPos = len; ++ } ++ ++ else if (c=='\004') { /* ^D: delete character at curPos */ ++ if (curPos==len) return(-1); ++ xvbcopy(&DialogFileName[curPos+1], &DialogFileName[curPos], (size_t) (len-curPos)); ++ } ++ ++ else if (c=='\002') { /* ^B: move backwards char */ ++ if (curPos==0) return(-1); ++ curPos--; ++ } ++ ++ else if (c=='\006') { /* ^F: move forwards char */ ++ if (curPos==len) return(-1); ++ curPos++; ++ } ++ ++ else if (c=='\012' || c=='\015') { /* CR(\r) or LF(\n) */ ++ FakeButtonPress(&msbut[MS_BOK]); ++ } ++ ++ else if (c=='\033') { /* ESC = Cancel */ ++ FakeButtonPress(&msbut[MS_BCANC]); ++ } ++ ++ else if (c=='\011') { /* tab = filename expansion */ ++ if (1 /* !autoComplete() */) XBell(theDisp, 0); ++ else { ++ curPos = strlen(DialogFileName); ++ } ++ } ++ ++ else return(-1); /* unhandled character */ ++ ++ showFNamMSD(); ++ ++ return(0); ++} ++ ++ ++/*******************************************/ ++int getInputCom() ++{ ++ static char *labels[] = { "\nOk", "\033Cancel" }; ++ int i; ++ ++ strcpy(input_command_ex, MGCSFX_DEFAULT_INPUT_COMMAND); ++ i = GetStrPopUp("Input External Command (Input is PNM):", labels, 2, ++ input_command_ex, 1024, "",0); ++ if (i == 0 && strlen(input_command_ex) != 0){ ++ input_command_ex_flag = 1; ++ return 1; ++ }else{ ++ input_command_ex_flag = 0; ++ return 0; ++ } ++} ++ ++int getOutputCom() ++{ ++ static char *labels[] = { "\nOk", "\033Cancel" }; ++ int i; ++ ++ strcpy(output_command_ex, MGCSFX_DEFAULT_OUTPUT_COMMAND); ++ i = GetStrPopUp("Input External Command (Output is PNM_RAW):", labels, 2, ++ output_command_ex, 1024, "",0); ++ if (i == 0 && strlen(output_command_ex) != 0){ ++ output_command_ex_flag = 1; ++ return 1; ++ }else{ ++ output_command_ex_flag = 0; ++ return 0; ++ } ++} ++ ++#ifdef SVR4 ++Sigfunc * ++xv_signal(signo, func) ++ int signo; ++ Sigfunc *func; ++{ ++ struct sigaction act, oact; ++ ++ act.sa_handler = func; ++ sigemptyset(&act.sa_mask); ++ act.sa_flags = 0; ++ act.sa_flags |= SA_RESTART; ++ ++ if (sigaction(signo, &act, &oact) < 0) ++ return SIG_ERR; ++ ++ return oact.sa_handler; ++} ++#endif ++ ++#endif /* HAVE_MGCSFX */ +diff -ruN xv-3.10a-bugfixes/xvmisc.c xv-3.10a-enhancements/xvmisc.c +--- xv-3.10a-bugfixes/xvmisc.c 2005-03-20 22:47:06.000000000 -0800 ++++ xv-3.10a-enhancements/xvmisc.c 2005-04-17 14:45:28.000000000 -0700 +@@ -103,10 +103,18 @@ + if (!usesize || !(i&WidthValue)) w = defw; + if (!usesize || !(i&HeightValue)) h = defh; + +- hints.flags |= USSize; ++ hints.flags |= USSize | PWinGravity; + +- if (i&XValue && i&XNegative) x = dispWIDE - w - abs(x); +- if (i&YValue && i&YNegative) y = dispHIGH - h - abs(y); ++ hints.win_gravity = NorthWestGravity; ++ if (i&XValue && i&XNegative) { ++ hints.win_gravity = NorthEastGravity; ++ x = dispWIDE - (w + 2 * bwidth) - abs(x); ++ } ++ if (i&YValue && i&YNegative) { ++ hints.win_gravity = (hints.win_gravity == NorthWestGravity) ? ++ SouthWestGravity : SouthEastGravity; ++ y = dispHIGH - (h + 2 * bwidth) - abs(y); ++ } + + + #define VROOT_TRANS +@@ -142,20 +150,19 @@ + if (!win) return(win); /* leave immediately if couldn't create */ + + +- XSetStandardProperties(theDisp, win, name, name, None, NULL, 0, &hints); +- + xwmh.input = True; + xwmh.flags = InputHint; + if (iconPix) { xwmh.icon_pixmap = iconPix; xwmh.flags |= IconPixmapHint; } +- XSetWMHints(theDisp, win, &xwmh); + + if (clname && strlen(clname)) { + classh.res_name = "xv"; + classh.res_class = clname; +- XSetClassHint(theDisp, win, &classh); + StoreDeleteWindowProp(win); + } + ++ XmbSetWMProperties(theDisp, win, name, name, NULL, 0, &hints, &xwmh, ++ clname ? &classh : NULL); ++ + return(win); + } + +@@ -232,28 +239,28 @@ + int i = CK_NONE; + + if (ks==XK_Up || ks==XK_KP_Up || +- ks==XK_KP_8 || ks==XK_F28) i=CK_UP; ++ ks==XK_F28) i=CK_UP; + + else if (ks==XK_Down || ks==XK_KP_Down || +- ks==XK_KP_2 || ks==XK_F34) i=CK_DOWN; ++ ks==XK_F34) i=CK_DOWN; + + else if (ks==XK_Left || ks==XK_KP_Left || +- ks==XK_KP_4 || ks==XK_F30) i=CK_LEFT; ++ ks==XK_F30) i=CK_LEFT; + + else if (ks==XK_Right || ks==XK_KP_Right || +- ks==XK_KP_6 || ks==XK_F32) i=CK_RIGHT; ++ ks==XK_F32) i=CK_RIGHT; + + else if (ks==XK_Prior || ks==XK_KP_Prior || +- ks==XK_KP_9 || ks==XK_F29) i=CK_PAGEUP; ++ ks==XK_F29) i=CK_PAGEUP; + + else if (ks==XK_Next || ks==XK_KP_Next || +- ks==XK_KP_3 || ks==XK_F35) i=CK_PAGEDOWN; ++ ks==XK_F35) i=CK_PAGEDOWN; + + else if (ks==XK_Home || ks==XK_KP_Home || +- ks==XK_KP_7 || ks==XK_F27) i=CK_HOME; ++ ks==XK_F27) i=CK_HOME; + + else if (ks==XK_End || ks==XK_KP_End || +- ks==XK_KP_1 || ks==XK_F33) i=CK_END; ++ ks==XK_F33) i=CK_END; + + else i = CK_NONE; + +@@ -503,6 +510,11 @@ + as we have to keep the alloc'd colors around, but we don't want anything + else to stay */ + ++#ifdef AUTO_EXPAND ++ chdir(initdir); ++ Vdsettle(); ++#endif ++ + if (!theDisp) exit(i); /* called before connection opened */ + + if (useroot && i==0) { /* save the root info */ +@@ -526,6 +538,26 @@ + if (tiffW) XDestroyWindow(theDisp, tiffW); + #endif + ++#ifdef HAVE_PNG ++ if (pngW) XDestroyWindow(theDisp, pngW); ++#endif ++ ++#ifdef HAVE_PCD ++ if (pcdW) XDestroyWindow(theDisp, pcdW); ++#endif ++ ++#ifdef HAVE_PIC2 ++ if (pic2W) XDestroyWindow(theDisp, pic2W); ++#endif ++ ++#ifdef HAVE_MGCSFX ++ if (mgcsfxW) XDestroyWindow(theDisp, mgcsfxW); ++#endif ++ ++#ifdef HAVE_PNG ++ if (pngW) XDestroyWindow(theDisp, pngW); ++#endif ++ + /* if NOT using stdcmap for images, free stdcmap */ + if (colorMapMode != CM_STDCMAP) { + int j; +@@ -722,6 +754,26 @@ + #ifdef HAVE_TIFF + if (tiffW) XDefineCursor(theDisp, tiffW, otherc); + #endif ++ ++#ifdef HAVE_PNG ++ if (pngW) XDefineCursor(theDisp, pngW, otherc); ++#endif ++ ++#ifdef HAVE_PNG ++ if (pngW) XDefineCursor(theDisp, pngW, otherc); ++#endif ++ ++#ifdef HAVE_PCD ++ if (pcdW) XDefineCursor(theDisp, pcdW, otherc); ++#endif ++ ++#ifdef HAVE_PIC2 ++ if (pic2W) XDefineCursor(theDisp, pic2W, otherc); ++#endif ++ ++#ifdef HAVE_MGCSFX ++ if (mgcsfxW) XDefineCursor(theDisp, mgcsfxW, otherc); ++#endif + } + + +@@ -921,7 +973,7 @@ + void XVCreatedFile(fullname) + char *fullname; + { +- /* called whenever a file has been deleted. Updates browser & dir windows, ++ /* called whenever a file has been created. Updates browser & dir windows, + if necessary */ + + BRCreatedFile(fullname); +@@ -1006,6 +1058,9 @@ + ((rv=(char *) getenv("cwd"))==NULL)) rv = "./"; + strcpy(buf, rv); + } ++#ifdef AUTO_EXPAND ++ Vdtodir(buf); ++#endif + } + + +diff -ruN xv-3.10a-bugfixes/xvml.c xv-3.10a-enhancements/xvml.c +--- xv-3.10a-bugfixes/xvml.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvml.c 2005-04-17 22:57:34.000000000 -0700 +@@ -0,0 +1,989 @@ ++/* ++ * xvml.c - makes text item structure for multi-lingual textviewer. ++ * ++ * Entry Points: ++ * struct ml_text *ml_draw_text() ++ * struct context *ml_create_context() ++ * int ml_set_charsets() ++ * void get_monofont_size() ++ */ ++ ++#include "xv.h" ++#include <X11/Xresource.h> ++ ++#ifdef TV_MULTILINGUAL /* whole this file. */ ++ ++#include "xvml.h" ++#define HAVE_STRDUP 1 ++#define USE_MULE_EXTENSION ++ ++#ifndef __STDC__ ++#define CHAR char ++#else ++#define CHAR int ++#endif ++ ++#define CODE_SI 0x0e /* LS0 */ ++#define CODE_SO 0x0f /* LS1 */ ++#define CODE_SS2 ((unsigned char) 0x8e) ++#define CODE_SS3 ((unsigned char) 0x8f) ++ ++int ml_tab_width = 64; /* dots */ ++ ++struct charset { ++ int bpc; /* bytes per char */ ++ int noc; /* number of chars */ ++ char designator; ++ char *registry; ++ int bit7; ++ ++ int loaded; ++ char *fontname; ++ ++ XFontStruct *fs; ++} charset[] = { ++ { 1, 94, 'B', "iso8859-1", 0, 0, NULL, NULL}, ++ { 1, 96, 'A', "iso8859-1", 1, 0, NULL, NULL}, ++ { 1, 94, '0', "omron_udc_zh-0", 0, 0, NULL, NULL}, ++ { 1, 94, '2', "mulearabic-0", 0, 0, NULL, NULL}, ++ { 1, 94, '3', "mulearabic-1", 0, 0, NULL, NULL}, ++ { 1, 94, '4', "mulearabic-2", 0, 0, NULL, NULL}, ++ { 1, 94, 'J', "jisx0201.1976-0", 0, 0, NULL, NULL}, ++ { 1, 96, '0', "muleipa-1", 1, 0, NULL, NULL}, ++ { 1, 96, '1', "viscii1.1-1", 1, 0, NULL, NULL}, ++ { 1, 96, '2', "viscii1.1-1", 1, 0, NULL, NULL}, ++ { 1, 96, 'B', "iso8859-2", 1, 0, NULL, NULL}, ++ { 1, 96, 'C', "iso8859-3", 1, 0, NULL, NULL}, ++ { 1, 96, 'D', "iso8859-4", 1, 0, NULL, NULL}, ++ { 1, 96, 'T', "tis620.1986-0", 1, 0, NULL, NULL}, ++ { 1, 96, 'F', "iso8859-7", 1, 0, NULL, NULL}, ++ { 1, 96, 'G', "iso8859-6", 1, 0, NULL, NULL}, ++ { 1, 96, 'H', "iso8859-8", 1, 0, NULL, NULL}, ++ { 1, 94, 'I', "jisx0201.1976-0", 1, 0, NULL, NULL}, ++ { 1, 96, 'L', "iso8859-5", 1, 0, NULL, NULL}, ++ { 1, 96, 'M', "iso8859-9", 1, 0, NULL, NULL}, ++ { 2, 94, '2', "ethio-0", 0, 0, NULL, NULL}, ++ { 2, 94, '@', "jisx0208.1978", 0, 0, NULL, NULL}, ++ { 2, 94, 'A', "gb2312.1980-0", 0, 0, NULL, NULL}, ++ { 2, 94, 'B', "jisx0208.1983-0", 0, 0, NULL, NULL}, ++ { 2, 94, 'C', "ksc5601.1987-0", 0, 0, NULL, NULL}, ++ { 2, 94, 'D', "jisx0212.1990-0", 0, 0, NULL, NULL}, ++ { 2, 94, '0', "big5.eten-0", 0, 0, NULL, NULL}, ++ { 2, 94, '1', "big5.hku-0", 0, 0, NULL, NULL}, ++ /* End Mark */ ++ { 0, 0, 0, NULL, 0, 0, NULL, NULL}, ++}; ++#define NR_CHARSETS ((int) (sizeof charset / sizeof charset[0])) ++ ++static struct charset *ascii = NULL; ++ ++struct context { ++ struct charset *g[4]; ++ struct charset **gl, **gr; ++ struct charset **ss; ++ int eol; /* 0: \n, 1: \r\n, 2: \r, 3: any */ ++ int valid[4]; /* g[i] is valid? */ ++ int short_form; /* allow shortened designator sequence? */ ++ int lock_shift; /* allow locking shift? */ ++ ++ unsigned char *cbuf, *cbp; ++ struct ml_text text; ++ int line; ++ int delta; ++ int toolong; ++ ++ Display *dpy; ++ Screen *scr; ++ Window root_win; ++}; ++#define DPY (context->dpy) ++#define SCR (context->scr) ++#define ROOT_WIN (context->root_win) ++ ++static unsigned char *escape_sequence PARM((unsigned char *)); ++static unsigned char *designator_sequence PARM((unsigned char *)); ++static void locking_shift PARM((unsigned CHAR)); ++static void single_shift PARM((unsigned CHAR)); ++static void put_unknown_char PARM((unsigned CHAR)); ++static struct charset *search_charset PARM((int, int, int)); ++static void pack_string PARM((struct charset *, ++ unsigned char *, int)); ++static void init_xrm PARM((void)); ++static void init_xrm_fonts PARM((void)); ++static void init_xrm_tab PARM((void)); ++#ifndef HAVE_STRDUP ++static char *strdup PARM((char *)); ++#endif ++ ++static char *default_fonts[] = { /* default for xrm_fonts */ ++ "-sony-fixed-medium-r-normal--16-*-*-*-*-*-iso8859-1", ++ "-jis-fixed-medium-r-normal--16-*-*-*-*-*-jisx0208.1983-0", ++}; ++static int xrm_nfonts; ++static char **xrm_fonts; ++ ++static struct context *context; /* current context */ ++ ++struct ml_text *ml_draw_text(ctx, string, len) ++ struct context *ctx; ++ char *string; ++ int len; ++{ ++ unsigned char *str = (unsigned char *) string; ++ unsigned char *estr = str + len; ++ ++ context = ctx; ++ ++ if(ascii == NULL){ ++ fputs("ml_draw_text: call ml_set_charsets, first.\n", stderr); ++ return NULL; ++ } ++ ++ if(!str) ++ return &context->text; ++ ++ WaitCursor(); ++ ++ if (context->text.maxlines != 0) { ++ struct ml_text *tp = &context->text; ++ struct ml_line *lp; ++ int i; ++ for (i = tp->nlines, lp = tp->lines; i > 0; i--, lp++) { ++ if (lp->maxitems != 0) ++ free((char *) lp->items); ++ } ++ free((char *) tp->lines); ++ tp->maxlines = tp->nlines = 0; ++ } ++ if (context->cbuf != NULL) ++ free((char *) context->cbuf); ++ context->cbp = (unsigned char *) malloc((size_t) len * 8);/* all \xxx */ ++ context->cbuf = context->cbp; ++ context->line = 0; ++ context->delta = 0; ++ context->ss = NULL; ++ ++ while(str < estr){ ++ if((*str & 0x80) == 0){ /* left half */ ++ struct charset *cs = context->ss ? *context->ss : *context->gl; ++ unsigned char min_char, max_char; ++ if (cs != NULL) { ++ if(cs->noc == 94){ ++ min_char = 0x21; ++ max_char = 0x7e; ++ }else{ ++ min_char = 0x20; ++ max_char = 0x7f; ++ } ++ } ++ ++ if (cs == NULL) ++ put_unknown_char(*str++); ++ else if(*str < min_char || *str > max_char){ /* C1 */ ++ switch(*str){ ++ case ' ': ++ { ++ unsigned char *p = str + 1; ++ while (*p == ' ' && p < estr) ++ p++; ++ pack_string(ascii, str, (int) (p - str)); ++ str = p; ++ } ++ break; ++ ++ case '\t': ++ pack_string(ascii, str++, 0); ++ break; ++ ++ case '\n': ++ switch (context->eol) { ++ case 0: /* unix type eol */ ++ pack_string(ascii, str, 0); ++ WaitCursor(); ++ str++; ++ break; ++ case 1: /* dos type eol */ ++ case 2: /* mac type eol */ ++ put_unknown_char('\n'); ++ str++; ++ break; ++ case 3: /* any type eol */ ++ pack_string(ascii, str++, 0); ++ while (*str == '\n' || *str == '\r') ++ str++; ++ WaitCursor(); ++ break; ++ } ++ break; ++ ++ case '\r': ++ switch (context->eol) { ++ case 0: ++ put_unknown_char('\r'); ++ str++; ++ break; ++ case 1: ++ str++; ++ if (*str == '\n') ++ pack_string(ascii, str++, 0); ++ else ++ put_unknown_char('\r'); ++ break; ++ case 2: ++ pack_string(ascii, str, 0); ++ WaitCursor(); ++ str++; ++ break; ++ case 3: ++ pack_string(ascii, str++, 0); ++ while (*str == '\n' || *str == '\r') ++ str++; ++ WaitCursor(); ++ break; ++ } ++ break; ++ ++ case '\033': ++ { ++ unsigned char *p; ++ str++; ++ if((p = escape_sequence(str)) == str) ++ put_unknown_char('\033'); ++ else ++ str = p; ++ } ++ break; ++ ++ case CODE_SI: ++ case CODE_SO: ++ if (!context->lock_shift) ++ put_unknown_char((unsigned int) *str++); ++ else ++ locking_shift((unsigned int) *str++); ++ break; ++ ++ default: ++ put_unknown_char((unsigned int) *str++); ++ } ++ }else{ /* GL */ ++ if (context->ss != NULL) { ++ pack_string(cs, str, 1); ++ str += cs->bpc; ++ context->ss = NULL; ++ } else { ++ int n; ++ ++ if (cs->bpc == 1) { ++ unsigned char *p = str; ++ for (n = 0; p < estr; n++) { ++ if (*p < min_char || *p > max_char) ++ break; ++ p++; ++ } ++ pack_string(cs, str, n); ++ str = p; ++ } else { ++ unsigned char *p = str; ++ for (n = 0; p < estr - 1; n++) { ++ if (*p < min_char || *p > max_char || ++ *(p + 1) < min_char || *(p + 1) > max_char) ++ break; ++ p += 2; ++ } ++ if (n > 0) ++ pack_string(cs, str, n); ++ else ++ put_unknown_char(*p++); ++ str = p; ++ } ++ } ++ } ++ }else{ /* right half */ ++ struct charset *cs = context->ss ? *context->ss : *context->gr; ++ unsigned char min_char, max_char; ++ if (cs != NULL) { ++ if(cs->noc == 94){ ++ min_char = 0xa1; ++ max_char = 0xfe; ++ }else{ ++ min_char = 0xa0; ++ max_char = 0xff; ++ } ++ } ++ ++ if (cs == NULL) ++ put_unknown_char(*str++); ++ else if(*str < min_char || *str > max_char){ /* C2 */ ++ unsigned char c = *str++; ++ switch(c){ ++ case CODE_SS2: ++ case CODE_SS3: ++ single_shift((unsigned CHAR) c); ++ break; ++ default: ++ put_unknown_char(c); ++ } ++ }else{ /* GR */ ++ if (context->ss != NULL) { ++ pack_string(cs, str, 1); ++ str += cs->bpc; ++ context->ss = NULL; ++ } else { ++ int n; ++ ++ if (cs->bpc == 1) { ++ unsigned char *p = str; ++ for (n = 0; p < estr; n++) { ++ if (*p < min_char || *p > max_char) ++ break; ++ p++; ++ } ++ pack_string(cs, str, n); ++ str = p; ++ } else { ++ unsigned char *p = str; ++ for (n = 0; p < estr - 1; n++) { ++ if (*p < min_char || *p > max_char || ++ *(p + 1) < min_char || *(p + 1) > max_char) ++ break; ++ p += 2; ++ } ++ if (n > 0) ++ pack_string(cs, str, n); ++ else ++ put_unknown_char(*p++); ++ str = p; ++ } ++ } ++ } ++ } ++ } ++ ++ { ++ struct ml_text *tp = &context->text; ++ struct ml_line *lp; ++ int i; ++ ++ tp->width = 0; ++ tp->height = 0; ++ for (lp = tp->lines, i = tp->nlines; i > 0; lp++, i--) { ++ if (lp->nitems == 0) { ++ lp->ascent = ascii->fs->ascent; ++ lp->descent = ascii->fs->descent; ++ } ++ if (tp->width < lp->width) ++ tp->width = lp->width; ++ tp->height += lp->ascent + lp->descent; ++ } ++ } ++ ++ SetCursors(-1); ++ return &context->text; ++} ++ ++static unsigned char *escape_sequence(str) ++ unsigned char *str; ++{ ++ unsigned char *p; ++ switch(*str){ ++ case '$': ++ case '(': case ')': case '*': case '+': ++ case '-': case '.': case '/': case ',': ++ if((p = designator_sequence(str)) == NULL) ++ return str; ++ return p; ++ case 'n': case 'o': case '~': case '}': case '|': ++ if (!context->lock_shift) ++ return str; ++ locking_shift(*str); ++ return str + 1; ++ case 'N': case 'O': ++ single_shift(*str); ++ return str + 1; ++ } ++ return str; ++ ++} ++ ++static unsigned char *designator_sequence(str) ++ unsigned char *str; ++{ ++ unsigned char *p = str; ++ int noc, bpc, n_g, shortened; ++ unsigned char des; ++ struct charset *cs; ++ ++ if(*p == '$'){ ++ bpc = 2; ++ p++; ++ }else ++ bpc = 1; ++ ++ switch(*p++){ ++ case '(': noc = 94; n_g = 0; des = *p++; shortened = 0; break; ++ case ')': noc = 94; n_g = 1; des = *p++; shortened = 0; break; ++ case '*': noc = 94; n_g = 2; des = *p++; shortened = 0; break; ++ case '+': noc = 94; n_g = 3; des = *p++; shortened = 0; break; ++#ifdef USE_MULE_EXTENSION ++ case ',': noc = 96; n_g = 0; des = *p++; shortened = 0; break; ++#endif ++ case '-': noc = 96; n_g = 1; des = *p++; shortened = 0; break; ++ case '.': noc = 96; n_g = 2; des = *p++; shortened = 0; break; ++ case '/': noc = 96; n_g = 3; des = *p++; shortened = 0; break; ++ case '@': noc = 94; n_g = 0; des = 'B'; shortened = 0; break; ++ case 'A': noc = 94; n_g = 0; des = 'A'; shortened = 1; break; ++ case 'B': noc = 94; n_g = 0; des = 'B'; shortened = 1; break; ++ default: return NULL; ++ } ++ if (!context->short_form && shortened) ++ return NULL; ++ ++ if((cs = search_charset(bpc, noc, des)) == NULL){ ++ if(DEBUG){ ++ fprintf(stderr, "designator_sequence: (%d,%d,%c) not found.\n", ++ bpc, noc, des); ++ } ++ return NULL; ++ } ++ if (!context->valid[n_g]) ++ return NULL; ++ context->g[n_g] = cs; ++ if(DEBUG){ ++ fprintf(stderr, ++ "designator_sequence: G%d is `%s'.\n", n_g, cs->registry); ++ } ++ return p; ++} ++ ++static void locking_shift(c) ++ unsigned CHAR c; ++{ ++ switch((unsigned char) c){ ++ case CODE_SI: context->gl = &context->g[0]; break; ++ case CODE_SO: context->gl = &context->g[1]; break; ++ case 'n': context->gl = &context->g[2]; break; ++ case 'o': context->gl = &context->g[3]; break; ++ case '~': context->gr = &context->g[1]; break; ++ case '}': context->gr = &context->g[2]; break; ++ case '|': context->gr = &context->g[3]; break; ++ } ++ if(DEBUG){ ++ fprintf(stderr, "locking_shift: (%d,%d).\n", ++ (int)(context->gl - context->g), ++ (int)(context->gr - context->g)); ++ } ++} ++ ++static void single_shift(c) ++ unsigned CHAR c; ++{ ++ switch((unsigned char) c){ ++ case CODE_SS2: context->ss = &context->g[2]; break; ++ case CODE_SS3: context->ss = &context->g[3]; break; ++ } ++} ++ ++ ++static void put_unknown_char(chr) ++ unsigned CHAR chr; ++{ ++ unsigned char c = chr; ++ ++ if(c < 0x20){ ++ unsigned char buf[2]; ++ buf[0] = '^'; ++ buf[1] = c + 0x40; ++ pack_string(ascii, buf, 2); ++ }else{ ++ unsigned char buf[4]; ++ buf[0] = '\\'; ++ buf[1] = ((c >> 6) & 07) + '0'; ++ buf[2] = ((c >> 3) & 07) + '0'; ++ buf[3] = ((c ) & 07) + '0'; ++ pack_string(ascii, buf, 4); ++ } ++} ++ ++struct context *ml_create_context(s) ++ Screen *s; ++{ ++ context = (struct context *) malloc(sizeof *context); ++ ++ context->g[0] = NULL; ++ context->g[1] = NULL; ++ context->g[2] = NULL; ++ context->g[3] = NULL; ++ context->gl = NULL; ++ context->gr = NULL; ++ context->ss = NULL; ++ ++ context->cbuf = NULL; ++ context->text.maxlines = context->text.nlines = 0; ++ context->line = 0; ++ context->delta = 0; ++ context->toolong = 0; ++ ++ DPY = DisplayOfScreen(s); ++ SCR = s; ++ ROOT_WIN = RootWindowOfScreen(s); ++ ++ return context; ++} ++ ++ ++int ml_set_charsets(ctx, sys) ++ struct context *ctx; ++ struct coding_system *sys; ++{ ++ int retval = 0; ++ int i; ++ ++ context = ctx; ++ ++ if(ascii == NULL){ ++ init_xrm(); ++ if((ascii = search_charset(1, 94, 'B')) == NULL){ ++ fputs("ml_set_charsets: ascii charset not found.\n", stderr); ++ Quit(1); ++ } ++ if (ascii->fs == NULL) { ++ fputs("ml_set_charsets: iso8859-1 font not found.\n", stderr); ++ Quit(1); ++ } ++ } ++ for(i = 0; i < 4; i++){ ++ switch(sys->design[i].bpc){ ++ case -1: /* make G[i] invalid */ ++ context->valid[i] = 0; ++ break; ++ ++ case 0: /* don't change */ ++ break; ++ ++ case 1: case 2: /* change it */ ++ if((context->g[i] = search_charset(sys->design[i].bpc, ++ sys->design[i].noc, ++ sys->design[i].des)) == NULL){ ++ fputs("ml_set_charsets: ", stderr); ++ fprintf(stderr, "(%d,%d,%c) is specified as G%d, ", ++ sys->design[i].bpc, sys->design[i].noc, ++ sys->design[i].des, i); ++ fputs("but not found. using `iso8859-1'.\n", stderr); ++ context->g[i] = ascii; ++ retval++; ++ } ++ context->valid[i] = 1; ++ break; ++ ++ default: /* error */ ++ fprintf(stderr,"ml_set_charsets: bad arguments of G%d. ", i); ++ fputs("using `iso8859-1'.\n", stderr); ++ context->g[i] = ascii; ++ retval++; ++ } ++ } ++ if((unsigned int) sys->gl < 4) ++ context->gl = &context->g[sys->gl]; ++ else{ ++ fprintf(stderr, "ml_set_charsets: bad number as GL. using G0.\n"); ++ context->gl = &context->g[0]; ++ } ++ if((unsigned int) sys->gr < 4) ++ context->gr = &context->g[sys->gr]; ++ else{ ++ fprintf(stderr, "ml_set_charsets: bad number as GR. using G0.\n"); ++ context->gr = &context->g[0]; ++ } ++ context->eol = sys->eol; ++ context->short_form = sys->short_form; ++ context->lock_shift = sys->lock_shift; ++ return retval; ++} ++ ++static struct charset *search_charset(bpc, noc, des) ++ int bpc, noc; ++ int des; ++{ ++ struct charset *cset; ++ for(cset = charset; cset->bpc != 0; cset++){ ++ if(cset->bpc == bpc && ++ cset->noc == noc && ++ cset->designator == (char) des){ ++ if(!cset->loaded){ ++#if 0 ++ int i, l; ++ l = strlen(cset->registry); ++ for (i = 0; i < xrm_nfonts; i++) { ++ int li = strlen(xrm_fonts[i]); ++ if (li > l) { ++ if (xrm_fonts[i][li - l - 1] == '-' && ++ strcmp(xrm_fonts[i] + li - l, ++ cset->registry) == 0) { ++ if ((cset->fs = XLoadQueryFont(DPY, xrm_fonts[i])) ++ != NULL) { ++ if (DEBUG) { ++ fprintf(stderr, "%s for %s\n", ++ xrm_fonts[i], cset->registry); ++ } ++ cset->fontname = xrm_fonts[i]; ++ break; ++ } else ++ SetISTR(ISTR_WARNING, ++ "%s: font not found.", xrm_fonts[i]); ++ } ++ } ++ } ++#else ++ int i, l; ++ l = strlen(cset->registry); ++ for (i = 0; i < xrm_nfonts && cset->fs == NULL; i++) { ++ int j, nfnts = 0; ++ char **fnts = XListFonts(DPY, xrm_fonts[i], ++ 65535, &nfnts); ++ for (j = 0 ; j < nfnts; j++) { ++ int ll = strlen(fnts[j]); ++ if (*(fnts[j] + ll - l - 1) == '-' && ++ strcmp(fnts[j] + ll - l, cset->registry)== 0) { ++ if ((cset->fs = XLoadQueryFont(DPY, fnts[j])) ++ != NULL) { ++ if (DEBUG) { ++ fprintf(stderr, "%s for %s\n", ++ fnts[j], cset->registry); ++ } ++ cset->fontname = strdup(fnts[j]); ++ break; ++ } else ++ SetISTR(ISTR_WARNING, ++ "%s: font not found", fnts[j]); ++ } ++ } ++ if (fnts != NULL) ++ XFreeFontNames(fnts); ++ } ++#endif ++ if(cset->fs == NULL){ ++ SetISTR(ISTR_WARNING, ++ "font for %s not found.\nusing ascii font.", ++ cset->registry); ++ if (ascii != NULL) ++ cset->fs = ascii->fs; ++ } ++ ++ cset->loaded = 1; ++ } ++ return cset; ++ } ++ } ++ return NULL; ++} ++ ++static void pack_string(cs, str, len) ++ struct charset *cs; ++ unsigned char *str; ++ int len; /* number of chars(not bytes) */ ++{ ++ struct ml_text *mt = &context->text; ++ struct ml_line *lp; ++ XTextItem16 *ip; ++ ++ if (context->line == mt->maxlines) { ++ int oldmax = mt->maxlines; ++ if (mt->maxlines < 1) ++ mt->maxlines = 1; ++ else ++ mt->maxlines = 2 * mt->maxlines; ++ if (oldmax == 0) ++ mt->lines = (struct ml_line *) ++ malloc(sizeof(struct ml_line) * mt->maxlines); ++ else { ++ mt->lines = (struct ml_line *) ++ realloc(mt->lines, ++ sizeof(struct ml_line) * mt->maxlines); ++ } ++ } ++ lp = &mt->lines[context->line]; ++ if (mt->nlines == context->line) { ++ mt->nlines++; ++ lp->maxitems = 0; ++ lp->nitems = 0; ++ lp->width = 0; ++ lp->ascent = lp->descent = 0; ++ } ++ ++ if (len == 0) { ++ switch (*str) { ++ case '\n': ++ context->line++; ++ context->delta = 0; ++ context->toolong = 0; ++ break; ++ case '\t': ++ { ++ int nx, x = lp->width + context->delta; ++ nx = (x + ml_tab_width) / ml_tab_width * ml_tab_width; ++ context->delta += nx - x; ++ } ++ break; ++ } ++ return; ++ } ++ ++ if (context->toolong) ++ return; ++ if (lp->width > 30000) { ++ context->toolong = 1; ++ cs = ascii; ++ str = (unsigned char *) "..."; ++ len = 3; ++ } ++ ++ if (lp->nitems == lp->maxitems) { ++ int oldmax = lp->maxitems; ++ if (lp->maxitems < 1) ++ lp->maxitems = 1; ++ else ++ lp->maxitems = 2 * lp->maxitems; ++ if (oldmax == 0) ++ lp->items = (XTextItem16 *) ++ malloc(sizeof(XTextItem16) * lp->maxitems); ++ else ++ lp->items = (XTextItem16 *) ++ realloc(lp->items, ++ sizeof(XTextItem16) * lp->maxitems); ++ } ++ ip = &lp->items[lp->nitems++]; ++ ip->chars = (XChar2b *) context->cbp; ++ ip->nchars = len; ++ ip->delta = context->delta; ++ ip->font = cs->fs->fid; ++ context->cbp += 2 * len; ++ context->delta = 0; ++ ++ if (cs->bpc == 1) { ++ XChar2b *p; ++ unsigned char b7 = cs->bit7 ? 0x80 : 0; ++ int i; ++ for (i = len, p = ip->chars; i > 0; i--, p++) { ++ p->byte1 = '\0'; ++ p->byte2 = (*str++ & 0x7f) | b7; ++ } ++ } else { ++ XChar2b *p; ++ unsigned char b7 = cs->bit7 ? 0x80 : 0; ++ int i; ++ for (i = len, p = ip->chars; i > 0; i--, p++) { ++ p->byte1 = (*str++ & 0x7f) | b7; ++ p->byte2 = (*str++ & 0x7f) | b7; ++ } ++ } ++ ++ lp->width += XTextWidth16(cs->fs, ip->chars, ip->nchars); ++ if (lp->ascent < cs->fs->ascent) ++ lp->ascent = cs->fs->ascent; ++ if (lp->descent < cs->fs->descent) ++ lp->descent = cs->fs->descent; ++} ++ ++void get_monofont_size(wide, high) ++ int *wide, *high; ++{ ++ if (ascii == NULL) { ++ fputs("ml_draw_text: call ml_set_charsets, first.\n", stderr); ++ return; ++ } ++ *wide = ascii->fs->max_bounds.width; ++ *high = ascii->fs->ascent + ascii->fs->descent; ++} ++ ++static void init_xrm() ++{ ++ init_xrm_fonts(); ++ init_xrm_tab(); ++} ++ ++static void init_xrm_fonts() ++{ ++ char *p, *fns = XGetDefault(theDisp, "xv", "fontSet"); ++ int n; ++ if (fns == NULL) { ++ xrm_fonts = default_fonts; ++ xrm_nfonts = sizeof default_fonts / sizeof *default_fonts; ++ return; ++ } ++ while(*fns == ' ' || *fns == '\t') ++ fns++; ++ if (*fns == '\0') { ++ xrm_fonts = default_fonts; ++ xrm_nfonts = sizeof default_fonts / sizeof *default_fonts; ++ return; ++ } ++ fns = strdup(fns); ++ ++ n = 1; ++ for (p = fns; *p != '\0'; p++) { ++ if (*p == ',') ++ n++; ++ } ++ xrm_nfonts = n; ++ xrm_fonts = (char **) malloc(sizeof (char *) * xrm_nfonts); ++ for (n = 0, p = fns; n < xrm_nfonts && *p != '\0'; ) { ++ while (*p == ' ' || *p == '\t') ++ p++; ++ xrm_fonts[n++] = p; ++ while (1) { ++ char *q; ++ while (*p != ' ' && *p != '\t' && *p != ',' && *p != '\0') ++ p++; ++ q = p; ++ while (*q == ' ' || *q == '\t') ++ q++; ++ if (*q == ',' || *q == '\0') { ++ *p = '\0'; ++ p = q + 1; ++ break; ++ } else ++ p = q; ++ } ++ } ++ for ( ; n < xrm_nfonts; n++) ++ xrm_fonts[n] = ""; ++} ++ ++static void init_xrm_tab() ++{ ++ char *ts = XGetDefault(theDisp, "xv", "tabWidth"); ++ unsigned short tab; ++ if (ts == NULL) ++ tab = 64; ++ else { ++ char *ep; ++ long t; ++ int bad = 0; ++ t = strtol(ts, &ep, 0); ++ tab = (unsigned short) t; ++ if (ep != NULL) { ++ while (*ep == ' ' && *ep == '\t') ++ ep++; ++ if (*ep != '\0') ++ bad = 1; ++ } ++ if (tab != (long) (unsigned long) t) ++ bad = 1; ++ if (bad) { ++ SetISTR(ISTR_WARNING, "bad tab width."); ++ tab = 64; ++ } ++ } ++ ml_tab_width = tab; ++} ++ ++ ++#ifndef HAVE_STRDUP ++static char *strdup(str) ++ char *str; ++{ ++ return strcpy(malloc(strlen(str) + 1), str); ++} ++#endif ++ ++char *lookup_registry(d, b7) ++ struct design d; ++ int *b7; ++{ ++ int i; ++ for (i = 0; i < NR_CHARSETS; i++) { ++ if (charset[i].bpc == d.bpc && charset[i].noc == d.noc && ++ charset[i].designator == d.des) { ++ *b7 = charset[i].bit7; ++ return charset[i].registry; ++ } ++ } ++ return NULL; ++} ++ ++struct design lookup_design(registry, b7) ++ char *registry; ++ int b7; ++{ ++ struct design d; ++ int i; ++ d.bpc = 0; ++ d.noc = 0; ++ d.des = '\0'; ++ for (i = 0; i < NR_CHARSETS; i++) { ++ if (strcmp(charset[i].registry, registry) == 0 && ++ charset[i].bit7 == b7) { ++ d.bpc = charset[i].bpc; ++ d.noc = charset[i].noc; ++ d.des = charset[i].designator; ++ break; ++ } ++ } ++ return d; ++} ++ ++char *sjis_to_jis(orig, len, newlen) ++ char *orig; ++ int len, *newlen; ++{ ++ unsigned char *new; ++ unsigned char *p, *q, *endp; ++ if (len == 0) { ++ *newlen = 0; ++ return (char *) malloc((size_t) 1); ++ } ++ new = (unsigned char *) malloc((size_t) len * 4); /* big enough */ ++ for (p = (unsigned char *) orig, endp = p + len, q = new; p < endp; ) { ++ if ((*p & 0x80) == 0) /* 1 byte char */ ++ *q++ = *p++; ++ else if (*p >= 0x81 && *p <= 0x9f) { /* kanji 1st byte */ ++ unsigned char c1 = *p++; ++ unsigned char c2 = *p++; ++ if (c2 < 0x40 || c2 > 0xfc) { /* bad 2nd byte */ ++ *q++ = CODE_SS2; ++ *q++ = c1; ++ *q++ = CODE_SS2; ++ *q++ = c2; ++ } else { /* right 2nd byte */ ++ if (c2 <= 0x9e) { ++ if (c2 > 0x7f) ++ c2--; ++ c1 = (c1 - 0x81) * 2 + 1 + 0xa0; ++ c2 = (c2 - 0x40) + 1 + 0xa0; ++ } else { ++ c1 = (c1 - 0x81) * 2 + 2 + 0xa0; ++ c2 = (c2 - 0x9f) + 1 + 0xa0; ++ } ++ *q++ = c1; ++ *q++ = c2; ++ } ++ } else if (*p >= 0xe0 && *p <= 0xef) { /* kanji 1st byte */ ++ unsigned char c1 = *p++; ++ unsigned char c2 = *p++; ++ if (c2 < 0x40 || c2 > 0xfc) { /* bad 2nd byte */ ++ *q++ = CODE_SS2; ++ *q++ = c1; ++ *q++ = CODE_SS2; ++ *q++ = c2; ++ } else { /* right 2nd byte */ ++ if (c2 <= 0x9e) { ++ c1 = (c1 - 0xe0) * 2 + 63 + 0xa0; ++ c2 = (c2 - 0x40) + 1 + 0xa0; ++ } else { ++ c1 = (c1 - 0xe0) * 2 + 64 + 0xa0; ++ c2 = (c2 - 0x9f) + 1 + 0xa0; ++ } ++ *q++ = c1; ++ *q++ = c2; ++ } ++ } else { /* katakana or something */ ++ *q++ = CODE_SS2; ++ *q++ = *p++; ++ } ++ } ++ *newlen = q - new; ++ ++ return (char *) realloc(new, (size_t) *newlen); ++} ++ ++#endif /* TV_MULTILINGUAL */ +diff -ruN xv-3.10a-bugfixes/xvml.h xv-3.10a-enhancements/xvml.h +--- xv-3.10a-bugfixes/xvml.h 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvml.h 2005-04-17 22:57:45.000000000 -0700 +@@ -0,0 +1,96 @@ ++#ifndef MLVIEW_H ++#define MLVIEW_H ++ ++/* ++ * What is this? ++ * ++ * It is a package to show multi-lingual text. ++ * ++ * How to use? ++ * ++ * 1. Call ml_set_screen(Screen *scr); ++ * Tell this package the screen you use. ++ * ++ * 2. Call ml_set_charsets(struct char_spec spec[4], int gl, int gr); ++ * Tell this package the initial charsets. ++ * Gn is set to the charset specified by spec[n], respectively. ++ * GL and GR are set to G[gl] and G[gr], respectively. ++ * If first call, iso8859-1 font is loaded. ++ * ++ * 3. Call ml_draw_text(char *string); ++ * It Creates a bitmap, and returns it to you. ++ * If something goes wrong, it returns None. ++ * DON'T free the returned pixmaps!! ++ * ++ * BUGS: ++ * - Amharic and Tigrigna characters are strange. ++ * - Big5 is not supported. ++ * - Reverse direction is not supported. ++ * - Composing is not supported. ++ * - Cantonese can't be shown. ++ * - Texts which have many lines are buggy. ++ * ++ * NOTE: ++ * - Shifted JIS and Shifted GB must be converted to iso2022 in advance. ++ * ++ * Example of parameters to ml_set_charsets: ++ * - EUC-Japan ++ * spec = { {1, 94, 'B'}, G0 is US-ASCII ++ * {2, 94, 'B'}, G1 is JIS X0208 ++ * {1, 94, 'J'}, G2 is (right-half of)JIS X0201 ++ * {2, 94, 'D'} }; G3 is JIS X0212 ++ * gl = 0; GL is G0 ++ * gr = 1; GR is G1 ++ * ++ * - Compound Text ++ * spec = { {1, 94, 'B'}, G0 is US-ASCII ++ * {1, 96, 'A'}, G1 is Latin-1 ++ * {1, 94, 'B'}, G2 is US-ASCII (maybe unused) ++ * {1, 94, 'B'} }; G3 is US-ASCII (maybe unused) ++ * gl = 0; GL is G0 ++ * gr = 1; GR is G1 ++ * ++ * - Korean Mail ++ * spec = { {1, 94, 'B'}, G0 is US-ASCII ++ * {2, 94, 'C'}, G1 is KSC5601 ++ * {1, 94, 'B'}, G2 is US-ASCII (maybe unused) ++ * {1, 94, 'B'} }; G3 is US-ASCII (maybe unused) ++ * gl = 0; GL is G0 ++ * gl = 1; GR is G1 ++ */ ++ ++struct coding_system { ++ struct design { ++ int bpc; /* byte per char if 1 or 2, ++ don't touch if 0, or ++ don't use if -1.*/ ++ int noc; /* number of chars (94 or 96) */ ++ char des; /* designator ('A', 'B', ...) */ ++ } design[4]; ++ int gl, gr; ++ int eol; ++ int short_form; ++ int lock_shift; ++}; ++ ++struct ml_text { ++ int maxlines, nlines; ++ struct ml_line { ++ int maxitems, nitems; ++ int width, ascent, descent; ++ XTextItem16 *items; ++ } *lines; ++ int width, height; ++}; ++ ++struct context; ++struct ml_text *ml_draw_text PARM((struct context *, char *, int)); ++struct context *ml_create_context PARM((Screen *)); ++int ml_set_charsets PARM((struct context *, ++ struct coding_system *)); ++void get_monofont_size PARM((int *, int *)); ++char *sjis_to_jis PARM((char *, int, int *)); ++char *lookup_registry PARM((struct design, int *)); ++struct design lookup_design PARM((char *, int)); ++ ++#endif +diff -ruN xv-3.10a-bugfixes/xvpbm.c xv-3.10a-enhancements/xvpbm.c +--- xv-3.10a-bugfixes/xvpbm.c 2005-04-03 14:25:28.000000000 -0700 ++++ xv-3.10a-enhancements/xvpbm.c 2005-04-17 14:04:22.000000000 -0700 +@@ -23,6 +23,15 @@ + */ + + ++typedef unsigned short ush; ++typedef unsigned char uch; ++ ++#define alpha_composite(composite, fg, alpha, bg) { \ ++ ush temp = ((ush)(fg)*(ush)(alpha) + \ ++ (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \ ++ (composite) = (uch)((temp + (temp >> 8)) >> 8); \ ++} ++ + #define TRUNCSTR "File appears to be truncated." + + static int garbage; +@@ -31,6 +40,7 @@ + static int loadpbm PARM((FILE *, PICINFO *, int)); + static int loadpgm PARM((FILE *, PICINFO *, int, int)); + static int loadppm PARM((FILE *, PICINFO *, int, int)); ++static int loadpam PARM((FILE *, PICINFO *, int, int)); + static int getint PARM((FILE *, PICINFO *)); + static int getbit PARM((FILE *, PICINFO *)); + static int getshort PARM((FILE *)); +@@ -38,10 +48,83 @@ + + static char *bname; + ++ ++#ifdef HAVE_MGCSFX ++/* ++ * When file read or file write is fail, probably it's caused by ++ * reading from pipe which has no data yet, or writing to pipe ++ * which is not ready yet. ++ * Then we can use system call select() on descriptor of pipe and wait. ++ * If you want, change 'undef' to 'define' in the following line. ++ * This feature is performance-killer. ++ */ ++#undef FIX_PIPE_ERROR ++ ++#ifdef __osf__ ++# ifdef __alpha ++# define FIX_PIPE_ERROR ++# endif ++#endif ++ ++#endif /* HAVE_MGCSFX */ ++ ++ ++#ifdef FIX_PIPE_ERROR ++ ++int pipefdr; ++ ++struct timeval timeout; ++int width; ++fd_set fds; ++ ++static void ready_read() ++{ ++ if(pipefdr < 0) return; /* if file descriptor is not pipe, OK */ ++ WaitCursor(); ++ ++reselect: ++ /* setting of timeout */ ++ timeout.tv_sec = 1; /* 1 sec */ ++ timeout.tv_usec = 0; /* 0 usec */ ++ ++ FD_ZERO(&fds); /* clear bits */ ++ FD_SET(pipefdr, &fds); /* set bit of fd in fds */ ++ ++ /* number of file descriptor to want check (0 $B!A(B width-1) */ ++ width = pipefdr + 1; ++ ++ /* select returns number of file descriptors */ ++ if (select(width, &fds, NULL, NULL, &timeout) < 0){ ++ if(DEBUG){ ++ fprintf(stderr, "No file descriptors can't selected, waiting...\n"); ++ } ++ goto reselect; ++ } ++ ++ if (FD_ISSET(pipefdr, &fds)){ ++ /* Now, descriptor of pipe is ready to read */ ++ return; ++ }else{ ++ if(DEBUG){ ++ fprintf(stderr, "Can't read from pipe yet, waiting...\n"); ++ } ++ goto reselect; ++ } ++ ++} ++#endif /* FIX_PIPE_ERROR */ ++ + /*******************************************/ ++#ifdef HAVE_MGCSFX ++int LoadPBM(fname, pinfo, fd) ++ char *fname; ++ PICINFO *pinfo; ++ int fd; ++#else + int LoadPBM(fname, pinfo) + char *fname; + PICINFO *pinfo; ++#endif /* HAVE_MGCSFX */ + /*******************************************/ + { + /* returns '1' on success */ +@@ -50,6 +133,10 @@ + int c, c1; + int maxv, rv; + ++#ifdef FIX_PIPE_ERROR ++ pipefdr = fd; ++#endif ++ + garbage = maxv = rv = 0; + bname = BaseName(fname); + +@@ -57,6 +144,22 @@ + pinfo->comment = (char *) NULL; + + ++#ifdef HAVE_MGCSFX ++ if(fd < 0){ ++ /* open the file */ ++ fp = xv_fopen(fname,"r"); ++ if (!fp) return (pbmError(bname, "can't open file")); ++ ++ /* compute file length */ ++ fseek(fp, 0L, 2); ++ filesize = ftell(fp); ++ fseek(fp, 0L, 0); ++ }else{ ++ fp = fdopen(fd, "r"); ++ if (!fp) return (pbmError(bname, "can't open file")); ++ filesize = 0; /* dummy */ ++ } ++#else + /* open the file */ + fp = xv_fopen(fname,"r"); + if (!fp) return (pbmError(bname, "can't open file")); +@@ -65,6 +168,7 @@ + fseek(fp, 0L, 2); + filesize = ftell(fp); + fseek(fp, 0L, 0); ++#endif /* HAVE_MGCSFX */ + + + /* read the first two bytes of the file to determine which format +@@ -73,7 +177,8 @@ + "P6" = raw pixmap */ + + c = getc(fp); c1 = getc(fp); +- if (c!='P' || c1<'1' || c1>'6') return(pbmError(bname, "unknown format")); ++ if (c!='P' || c1<'1' || (c1>'6' && c1!='8')) /* GRR alpha */ ++ return(pbmError(bname, "unknown format")); + + /* read in header information */ + pinfo->w = getint(fp, pinfo); pinfo->h = getint(fp, pinfo); +@@ -104,6 +209,7 @@ + if (c1=='1' || c1=='4') rv = loadpbm(fp, pinfo, c1=='4' ? 1 : 0); + else if (c1=='2' || c1=='5') rv = loadpgm(fp, pinfo, c1=='5' ? 1 : 0, maxv); + else if (c1=='3' || c1=='6') rv = loadppm(fp, pinfo, c1=='6' ? 1 : 0, maxv); ++ else if (c1=='8') rv = loadpam(fp, pinfo, 1 , maxv); + + fclose(fp); + +@@ -248,7 +354,20 @@ + } + } + else { ++#ifdef FIX_PIPE_ERROR ++ reread: ++ numgot += fread(pic8 + numgot, (size_t) 1, (size_t) w*h - numgot, fp); /* read raw data */ ++ if(errno == EINTR){ ++ if(DEBUG){ ++ fprintf(stderr, ++ "Can't read all data from pipe, call select and waiting...\n"); ++ } ++ ready_read(); ++ goto reread; ++ } ++#else + numgot = fread(pic8, (size_t)1, (size_t)npixels, fp); /* read raw data */ ++#endif + } + } + +@@ -315,7 +434,20 @@ + } + } + else { ++#ifdef FIX_PIPE_ERROR ++ reread: ++ numgot += fread(pic24 + numgot, (size_t) 1, (size_t) w*h*3 - numgot, fp); /* read data */ ++ if(errno == EINTR){ ++ if(DEBUG){ ++ fprintf(stderr, ++ "Can't read all data from pipe, call select and waiting...\n"); ++ } ++ ready_read(); ++ goto reread; ++ } ++#else + numgot = fread(pic24, (size_t) 1, (size_t) bufsize, fp); /* read data */ ++#endif + } + } + +@@ -341,6 +473,122 @@ + } + + ++/*******************************************/ ++static int loadpam(fp, pinfo, raw, maxv) /* unofficial RGBA extension */ ++ FILE *fp; ++ PICINFO *pinfo; ++ int raw, maxv; ++{ ++ byte *p, *pix, *pic24, *linebuf, scale[256], bgR, bgG, bgB, r, g, b, a; ++ int i, j, bitshift, w, h, npixels, bufsize, linebufsize, holdmaxv; ++ ++ w = pinfo->w; ++ h = pinfo->h; ++ ++ npixels = w * h; ++ bufsize = 3*npixels; ++ linebufsize = 4*w; ++ if (w <= 0 || h <= 0 || npixels/w != h || bufsize/3 != npixels || ++ linebufsize/4 != w) ++ return pbmError(bname, "image dimensions too large"); ++ ++ /* allocate 24-bit image */ ++ pic24 = (byte *) calloc((size_t) bufsize, (size_t) 1); ++ if (!pic24) FatalError("couldn't malloc 'pic24' for PAM"); ++ ++ /* allocate line buffer for pre-composited RGBA data */ ++ linebuf = (byte *) malloc((size_t) linebufsize); ++ if (!linebuf) { ++ free(pic24); ++ FatalError("couldn't malloc 'linebuf' for PAM"); ++ } ++ ++ pinfo->pic = pic24; ++ pinfo->type = PIC24; ++ sprintf(pinfo->fullInfo, "PAM, %s format. (%ld bytes)", ++ (raw) ? "raw" : "ascii", filesize); ++ sprintf(pinfo->shrtInfo, "%dx%d PAM.", w, h); ++ pinfo->colType = F_FULLCOLOR; ++ ++ ++ /* if maxv>255, keep dropping bits until it's reasonable */ ++ holdmaxv = maxv; ++ bitshift = 0; ++ while (maxv>255) { maxv = maxv>>1; bitshift++; } ++ ++ ++ numgot = 0; ++ ++ if (!raw) { /* GRR: not alpha-ready */ ++ return pbmError(bname, "can't handle non-raw PAM image"); ++/* ++ for (i=0, pix=pic24; i<h; i++) { ++ if ((i&0x3f)==0) WaitCursor(); ++ for (j=0; j<w*3; j++, pix++) ++ *pix = (byte) (getint(fp, pinfo) >> bitshift); ++ } ++ */ ++ } ++ else { /* raw */ ++ if (holdmaxv>255) { /* GRR: not alpha-ready */ ++ return pbmError(bname, "can't handle PAM image with maxval > 255"); ++/* ++ for (i=0, pix=pic24; i<h; i++) { ++ if ((i&0x3f)==0) WaitCursor(); ++ for (j=0; j<w*3; j++,pix++) ++ *pix = (byte) (getshort(fp) >> bitshift); ++ } ++ */ ++ } ++ else { ++ if (have_imagebg) { /* GRR: alpha-ready */ ++ bgR = (imagebgR >> 8); ++ bgG = (imagebgG >> 8); ++ bgB = (imagebgB >> 8); ++ } else { ++ bgR = bgG = bgB = 0; ++ } ++ for (i=0, pix=pic24; i<h; i++) { ++ numgot += fread(linebuf, (size_t) 1, (size_t) linebufsize, fp); /* read data */ ++ if ((i&0x3f)==0) WaitCursor(); ++ for (j=0, p=linebuf; j<w; j++) { ++ r = *p++; ++ g = *p++; ++ b = *p++; ++ a = *p++; ++ alpha_composite(*pix++, r, a, bgR) ++ alpha_composite(*pix++, g, a, bgG) ++ alpha_composite(*pix++, b, a, bgB) ++ } ++ } ++ } ++ } ++ ++ free(linebuf); ++ ++ /* in principle this could overflow, but not critical */ ++ if (numgot != w*h*4) pbmError(bname, TRUNCSTR); ++ ++ if (garbage) ++ return(pbmError(bname, "Garbage characters in image data.")); ++ ++ ++ /* have to scale up all RGB values (Conv24to8 expects RGB values to ++ range from 0-255) */ ++ ++ if (maxv<255) { ++ for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv; ++ ++ for (i=0, pix=pic24; i<h; i++) { ++ if ((i&0x3f)==0) WaitCursor(); ++ for (j=0; j<w*3; j++, pix++) *pix = scale[*pix]; ++ } ++ } ++ ++ return 1; ++} ++ ++ + + /*******************************************/ + static int getint(fp, pinfo) +diff -ruN xv-3.10a-bugfixes/xvpcd.c xv-3.10a-enhancements/xvpcd.c +--- xv-3.10a-bugfixes/xvpcd.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvpcd.c 2005-04-26 00:25:13.000000000 -0700 +@@ -0,0 +1,1307 @@ ++/* ++ * xvpcd.c - load routine for 'PhotoCD' format pictures ++ * ++ * LoadPCD(fname, pinfo, size) - loads a PhotoCD file ++ * ++ * This routine will popup a choice of which of the 5 available resolutions ++ * the user wants to choose, then load it as a 24 bit image. ++ * ++ * Copyright 1993 David Clunie, Melbourne, Australia. ++ * ++ * The outline of this is shamelessly derived from xvpbm.c to read the ++ * file, and xvtiffwr.c to handle the popup window and X stuff (X never ++ * has been my forte !), and the PhotoCD format information (though not ++ * the code) was found in Hadmut Danisch's (danisch@ira.uka.de) hpcdtoppm ++ * program in which he has reverse engineered the format by studying ++ * hex dumps of PhotoCDs ! After all who can afford the Kodak developer's ++ * kit, which none of us have seen yet ? Am I even allowed to mention these ++ * words (Kodak, PhotoCD) ? I presume they are registered trade marks. ++ * ++ * PS. I have no idea how Halmut worked out the YCC <-> RGB conversion ++ * factors, but I have calculated them from his tables and the results ++ * look good enough to me. ++ * ++ * Added size parameter to allow the schnautzer to create thumnails ++ * without requesting the size every time. ++ */ ++ ++#include "xv.h" ++#include <memory.h> ++ ++#ifdef HAVE_PCD ++ ++#define TRACE 0 ++#if TRACE ++# define trace(x) fprintf x ++#else ++# define trace(x) ++#endif ++ ++/* Comments on error-handling: ++ A truncated file is not considered a Major Error. The file is loaded, ++ and the rest of the pic is filled with 0's. ++ ++ Not being able to malloc is a Fatal Error. The program is aborted. */ ++ ++ ++#ifdef __STDC__ ++static void magnify(int, int, int, int, int, byte *); ++static int pcdError(char *, char *); ++static int gethuffdata(byte *, byte *, byte *, int, int); ++#else ++static void magnify(); ++static int pcdError(); ++static int gethuffdata(); ++#endif ++ ++#define wcurfactor 16 /* Call WaitCursor() every n rows */ ++ ++static int size; /* Set by window routines */ ++static int leaveitup;/* Cleared by docmd() when OK or CANCEL pressed */ ++static int goforit; /* Set to 1 if OK or 0 if CANCEL */ ++static FILE *fp; ++static CBUTT lutCB; ++ ++/* ++ * This "beyond 100%" table is taken from ImageMagick (gamma 2.2). ++ * Why there are 351 entries and not 346 as per Kodak documentation ++ * is a mystery. ++ */ ++static double rscale = 1.00, ++ gscale = 1.00, ++ bscale = 1.00; ++ ++static byte Y[351] = { ++ 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, 32, 33, 34, 35, 36, 37, 38, 39, 40, ++ 41, 42, 43, 45, 46, 47, 48, 49, 50, 51, ++ 52, 53, 54, 56, 57, 58, 59, 60, 61, 62, ++ 63, 64, 66, 67, 68, 69, 70, 71, 72, 73, ++ 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, ++ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, ++ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, ++ 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, ++ 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, ++ 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, 176, 177, ++ 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, ++ 188, 189, 190, 191, 192, 193, 193, 194, 195, 196, ++ 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, ++ 206, 207, 207, 208, 209, 210, 211, 211, 212, 213, ++ 214, 215, 215, 216, 217, 218, 218, 219, 220, 221, ++ 221, 222, 223, 224, 224, 225, 226, 226, 227, 228, ++ 228, 229, 230, 230, 231, 232, 232, 233, 234, 234, ++ 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, ++ 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, ++ 245, 246, 246, 247, 247, 247, 248, 248, 248, 249, ++ 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, ++ 251, 251, 252, 252, 252, 252, 252, 253, 253, 253, ++ 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, ++ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, ++ 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, ++ 255 ++}; ++ ++/*******************************************/ ++/* The size should be -1 for the popup to ask otherwise fast is assumed */ ++/* returns '1' on success */ ++/*******************************************/ ++int ++LoadPCD(char *fname, PICINFO *pinfo, int theSize) ++{ ++ long offset; ++ int mag; ++ int rotate; ++ byte header[3*0x800]; ++ byte *pic24, *luma, *chroma1, *chroma2, *ptr, *lptr, *c1ptr, *c2ptr; ++ int w, h, npixels, bufsize; ++ int row, col; ++ int huffplanes; ++ char *bname; ++ ++ bname = BaseName(fname); ++ pinfo->pic = NULL; ++ pinfo->comment = NULL; ++ ++ ++ /* ++ * open the file ++ */ ++ if((fp=fopen(fname,"r")) == NULL) ++ return pcdError(bname, "can't open file"); ++ ++ /* ++ * inspect the header ++ */ ++ if(fread(&header[0], 1, sizeof(header), fp) != sizeof(header)) ++ return pcdError(bname, "could not load PCD header"); ++ if(strncmp(&header[0x800], "PCD_", 4) != 0) ++ return pcdError(bname, "not a PCD file"); ++ rotate = header[0x0E02] & 0x03; ++ ++/* base/16 ++ - plain data starts at sector 1+2+1=4 ++ (numbered from 0, ie. the 5th sector) ++ - luma 192*128 = 24576 bytes (12 sectors) ++ + chroma1 96*64 = 6144 bytes (3 sectors) ++ + chroma2 96*64 = 6144 bytes (3 sectors) ++ = total 18 sectors ++ ++ - NB. "Plain" data is interleaved - 2 luma rows 192 wide, ++ then 1 of each of the chroma rows 96 wide ! ++ ++ base/4 ++ - plain data starts at sector 1+2+1+18+1=23 ++ - luma 384*256 = 98304 bytes (48 sectors) ++ + chroma1 192*128 = 24576 bytes (12 sectors) ++ + chroma2 192*128 = 24576 bytes (12 sectors) ++ = total 72 sectors ++ ++ - NB. "Plain" data is interleaved - 2 luma rows 384 wide, ++ then 1 of each of the chroma rows 192 wide ! ++ ++ base ++ - plain data starts at sector 1+2+1+18+1+72+1=96 ++ ++ - luma 768*512 = 393216 bytes (192 sectors) ++ + chroma1 384*256 = 98304 bytes (48 sectors) ++ + chroma2 384*256 = 98304 bytes (48 sectors) ++ = total 288 sectors ++ ++ - NB. "Plain" data is interleaved - 2 luma rows 768 wide, ++ then 1 of each of the chroma rows 384 wide ! ++ ++ 4base ++ - plain data for base is read ++ - luma data interpolated *2 ++ - chroma data interpolated *4 ++ ++ - cd_offset is 1+2+1+18+1+72+1+288=384 ++ - at cd_offset+4 (388) is huffman table ++ - at cd_offset+5 (389) is 4base luma plane ++ ++ (the sector at cd_offset+3 seems to contain 256 words each of ++ which is an offset presumably to the sector containing certain ++ rows ? rows/4 given 1024 possible rows. The rest of this sector ++ is filled with zeroes) ++ ++ ++ 16base ++ - plain data for base is read ++ - luma data interpolated *2 ++ - chroma data interpolated *4 ++ ++ - cd_offset is 1+2+1+18+1+72+1+288=384 ++ - at cd_offset+4 (388) is huffman table for 4 base ++ - at cd_offset+5 (389) is 4base luma plane ++ - luma plane interpolated *2 ++ ++ - cd_offset is set to current position (should be start of sector) ++ - at cd_offset+12 is huffman table for 16 base ++ - at cd_offset+14 is 16 base luma & 2 chroma planes which are read ++ (note that the luma plane comes first, with a sync pattern ++ announcing each row from 0 to 2047, then the two chroma planes ++ are interleaved by row, the row # being even from 0 to 2046, with ++ each row containing 1536 values, the chroma1 row coming first, ++ finally followed by a sync pattern with a row of 2048 announcing ++ the end (its plane seems to be set to 3, ie. chroma2) ++ - chroma planes interpolated *2 ++ ++ (the sector at cd_offset+10 & 11 seem to contain 1024 pairs of words ++ the first for luma and the second for chroma, each of ++ which is an offset presumably to the sector containing certain ++ rows ? rows/2 given 2048 possible rows) ++ ++Not yet implemented: ++ ++In order to do overskip for base and 4base, one has to reach the chroma ++data for 16 base: ++ ++ - for 4base, after reading the 4base luma plane (and presumably ++ skipping the chroma planes) one sets cd_offset to the start of ++ the "current" sector ++ ++ - for base, one has to skip the 4base data first: ++ - cd_offset is set to 384 ++ - at (cd_offset+3 sectors)[510] is a 16 bit word high byte 1st ++ containing an offset to the beginning of the 16base stuff ++ though there is then a loop until >30 0xff's start a sector ! ++ ++ - being now positioned after the end of the 4base stuff, ++ - at (cd_offset+10 sectors)[2] is a 16 bit word high byte 1st ++ containing an offset to the chroma planes. ++ - at cd_offset+12 is the set of huffman tables ++ ++ - for base, the 16base chroma planes are then halved ++*/ ++ ++ PCDSetParamOptions(bname); ++ if (theSize == -1) ++ { ++ PCDDialog(1); /* Open PCD Dialog box */ ++ SetCursors(-1); /* Somebody has already set it to wait :( */ ++ leaveitup=1; ++ goforit=0; ++ size = 1; ++ /* block until the popup window gets closed */ ++ while (leaveitup) { ++ int i; ++ XEvent event; ++ XNextEvent(theDisp, &event); ++ HandleEvent(&event, &i); ++ } ++ /* At this point goforit and size will have been set */ ++ if (!goforit) { ++ /* nothing allocated so nothing needs freeing */ ++ return 0; ++ } ++ WaitCursor(); ++ } ++ else ++ { ++ size = theSize; ++ goforit = 1; ++ } ++ ++ if(lutCB.val) ++ rscale = gscale = bscale = 255.0/346.0; ++ else ++ rscale = gscale = bscale = 1.0; ++ ++ switch (size) { ++ case 0: ++ pinfo->w = 192; ++ pinfo->h = 128; ++ offset=4*0x800; ++ mag=1; ++ huffplanes=0; ++ sprintf(pinfo->fullInfo, "PhotoCD, base/16 resolution"); ++ break; ++ ++ case 1: ++ pinfo->w = 384; ++ pinfo->h = 256; ++ offset=23*0x800; ++ mag=1; ++ huffplanes=0; ++ sprintf(pinfo->fullInfo, "PhotoCD, base/4 resolution"); ++ break; ++ ++ case 2: ++ default: ++ pinfo->w = 768; ++ pinfo->h = 512; ++ offset=96*0x800; ++ mag=1; ++ huffplanes=0; ++ sprintf(pinfo->fullInfo, "PhotoCD, base resolution"); ++ break; ++ ++ case 3: ++ pinfo->w = 1536; ++ pinfo->h = 1024; ++ offset=96*0x800; ++ mag=2; ++ huffplanes=1; ++ sprintf(pinfo->fullInfo, "PhotoCD, 4base resolution"); ++ break; ++ ++ case 4: ++ pinfo->w=3072; ++ pinfo->h=2048; ++ offset=96*0x800; ++ mag=4; ++ huffplanes=2; ++ sprintf(pinfo->fullInfo, "PhotoCD, 16base resolution"); ++ break; ++ } ++ ++ /* ++ * rotate? ++ */ ++ w = pinfo->w; ++ h = pinfo->h; ++ switch(rotate) { ++ case 0: ++ break; ++ ++ case 1: ++ case 3: ++ pinfo->w = h; ++ pinfo->h = w; ++ break; ++ ++ default: ++ fprintf(stderr, "unknown image rotate %d; assuming none\n", ++ rotate); ++ rotate = 0; ++ } ++ ++ /* ++ * allocate 24-bit image ++ */ ++ npixels = pinfo->w * pinfo->h; ++ bufsize = 3 * npixels; ++ if (pinfo->w <= 0 || pinfo->h <= 0 || npixels/pinfo->w != pinfo->h || ++ bufsize/3 != npixels) ++ FatalError("image dimensions out of range"); ++ ++ pinfo->pic = (byte *)malloc((size_t) bufsize); ++ if(!pinfo->pic) ++ FatalError("couldn't malloc '24-bit RGB plane'"); ++ ++ pinfo->type = PIC24; ++ sprintf(pinfo->shrtInfo, "%dx%d PhotoCD.", pinfo->w, pinfo->h); ++ pinfo->colType = F_FULLCOLOR; ++ pinfo->frmType = -1; ++ ++ if(fseek(fp, offset, SEEK_SET) == -1) { ++ free(pinfo->pic); ++ return pcdError(bname,"Can't find start of data."); ++ } ++ ++ pic24 = pinfo->pic; ++ ++ luma=(byte *)calloc(npixels,1); ++ if(!luma) { ++ free(pinfo->pic); ++ FatalError("couldn't malloc 'luma plane'"); ++ } ++ ++ chroma1=(byte *)calloc(npixels/4,1); ++ if(!chroma1) { ++ free(pinfo->pic); ++ free(luma); ++ FatalError("couldn't malloc 'chroma1 plane'"); ++ } ++ ++ chroma2=(byte *)calloc(npixels/4,1); ++ if(!chroma2) { ++ free(pinfo->pic); ++ free(luma); ++ free(chroma1); ++ FatalError("couldn't malloc 'chroma2 plane'"); ++ } ++ ++ /* Read 2 luma rows length w, then one of each chroma rows w/2 */ ++ /* If a mag factor is active, the small image is read into the */ ++ /* top right hand corner of the larger allocated image */ ++ ++ trace((stderr, "base image: start @ 0x%08lx (sector %ld.%ld)\n", ++ ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800)); ++ for(row=0,lptr=luma,c1ptr=chroma1,c2ptr=chroma2; row <h/mag; ++ row+=2,lptr+=w*2,c1ptr+=w/2,c2ptr+=w/2) { ++ if(fread(lptr, 1, w/mag, fp) != w/mag) { ++ pcdError(bname, "Luma plane too short."); ++ break; ++ } ++ if(fread(lptr+w, 1, w/mag, fp) != w/mag) { ++ pcdError(bname, "Luma plane too short."); ++ break; ++ } ++ if(fread(c1ptr, 1, w/2/mag, fp) != w/2/mag) { ++ pcdError(bname, "Chroma1 plane too short."); ++ break; ++ } ++ if(fread(c2ptr, 1, w/2/mag, fp) != w/2/mag) { ++ pcdError(bname, "Chroma2 plane too short."); ++ break; ++ } ++ if(row%wcurfactor == 0) ++ WaitCursor(); ++ } ++ trace((stderr, "base image: done @ 0x%08lx (sector %ld.%ld)\n", ++ ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800)); ++ ++ if(huffplanes) { ++ if(fseek(fp, 388*0x800, SEEK_SET) == -1) ++ return pcdError(bname, ++ "Can't find start of huffman tables."); ++ ++ magnify(2, h/mag, w/mag, h, w, luma); ++ magnify(2, h/2/mag, w/2/mag, h/2, w/2, chroma1); ++ magnify(2, h/2/mag, w/2/mag, h/2, w/2, chroma2); ++ ++ /* ++ * doesn't really touch the chroma planes which aren't ++ * present in 4base ++ */ ++ gethuffdata(luma, chroma1, chroma2, w, h/mag*2); ++ ++ /* ++ * if only doing 4base should probably fetch 16bases ++ * chroma planes here ++ */ ++ if(huffplanes == 2) { ++ /* ++ * This depends on gethuffdata() having grabbed ++ * things in 0x800 sectors AND still being ++ * positioned in the "last" sector of the data ++ * (cf. Hadmut's code which is positioned at start ++ * of the next sector) ++ */ ++ long offset = ftell(fp)/0x800+12; ++ ++ if(fseek(fp, offset*0x800, SEEK_SET) == 0) { ++ magnify(2,h/2,w/2,h,w,luma); ++ magnify(2,h/4,w/4,h/2,w/2,chroma1); ++ magnify(2,h/4,w/4,h/2,w/2,chroma2); ++ gethuffdata(luma,chroma1,chroma2,w,h); ++ } else ++ fprintf(stderr, "can't seek to 2nd huffman tables\n"); ++ } ++ } ++ fclose(fp); ++ ++ /* ++ * YCC -> R'G'B' and image rotate ++ */ ++ ptr=pic24; ++ lptr=luma; c1ptr=chroma1; c2ptr=chroma2; ++ for(row = 0; row < h; ++row) { ++ byte *rowc1ptr = c1ptr, ++ *rowc2ptr = c2ptr; ++ int k = 0; ++ ++ switch(rotate) { ++ case 1: ++ ptr = &pic24[row*3 + (w - 1)*h*3]; ++ k = -3*(h + 1); ++ break; ++ ++ case 3: ++ ptr = &pic24[(h - 1 - row)*3]; ++ k = 3*(h - 1); ++ break; ++ ++ default: ++ ptr = &pic24[row*w*3]; ++ k = 0; ++ break; ++ } ++ for(col = 0; col < w; ++col) { ++ double L = 1.3584*(double) *lptr++, ++ C1 = 2.2179*(double) (*c1ptr - 156), ++ C2 = 1.8215*(double) (*c2ptr - 137); ++ int r = rscale*(L + C2), ++ g = gscale*(L - 0.194*C1 - 0.509*C2), ++ b = bscale*(L + C1); ++ ++ if(lutCB.val) { ++ if(r < 0) r = 0; else if(r >= 255) r = 255; ++ if(g < 0) g = 0; else if(g >= 255) g = 255; ++ if(b < 0) b = 0; else if(b >= 255) b = 255; ++ } else { ++ if(r < 0) r = 0; else if(r >= 351) r = 350; ++ if(g < 0) g = 0; else if(g >= 351) g = 350; ++ if(b < 0) b = 0; else if(b >= 351) b = 350; ++ r = Y[r]; g = Y[g]; b = Y[b]; ++ } ++ *ptr++ = r; ++ *ptr++ = g; ++ *ptr++ = b; ++ ptr += k; ++ if(col & 1) { ++ ++c1ptr; ++ ++c2ptr; ++ } ++ } ++ if((row & 1) == 0) { ++ c1ptr = rowc1ptr; ++ c2ptr = rowc2ptr; ++ } ++ if(row%wcurfactor == 0) ++ WaitCursor(); ++ } ++ free(luma); free(chroma1); free(chroma2); ++ return 1; ++} ++ ++/* ++ * derived from Hadmut Danisch's interpolate() ++ */ ++static void ++magnify(int mag, /* power of 2 by which to magnify in place */ ++ int h, int w, /* the "start" unmag'd dimensions of the array */ ++ int mh, int mw, /* the real (maximum) dimensions of the array */ ++ byte *p) /* pointer to the data */ ++{ ++ int x,y,yi; ++ byte *optr,*nptr,*uptr; /* MUST be unsigned, else averaging fails */ ++ ++ while (mag > 1) { ++ ++ /* create every 2nd new row from 0 */ ++ /* even pixels being equal to the old, odd ones averaged with successor */ ++ /* special case being the last column which is just set equal to the */ ++ /* second last) ... */ ++ ++ for(y=0;y<h;y++) { ++ yi=h-1-y; ++ optr=p+ yi*mw + (w-1); /* last pixel of an old row */ ++ nptr=p+2*yi*mw + (2*w - 2); /* last pixel of a new row */ ++ ++ nptr[0]=nptr[1]=optr[0]; /* special cases */ ++ ++ for(x=1;x<w;x++) { ++ optr--; nptr-=2; /* next lower pixel(s) */ ++ nptr[0]=optr[0]; /* even pixels duped */ ++ nptr[1]=(((int)optr[0])+ ++ ((int)optr[1])+1)>>1; /* odd averaged */ ++ } ++ } ++ ++ /* Fill in odd rows, as average of prior & succeeding rows, with */ ++ /* even pixels average of one column, odd pixels average of two */ ++ ++ for(y=0;y<h-1;y++) { /* all but the last old row */ ++ optr=p + 2*y*mw; /* start of the new "even" rows */ ++ nptr=optr+mw; /* start of the next empty row */ ++ uptr=nptr+mw; /* start of the next again (even) */ ++ ++ for(x=0;x<w-1;x++) { /* for all cols except the last */ ++ nptr[0]=(((int)optr[0])+ ++ ((int)uptr[0])+1)>>1; /* even pixels */ ++ nptr[1]=(((int)optr[0])+ ++ ((int)optr[2])+ ++ ((int)uptr[0])+ ++ ((int)uptr[2])+2)>>2; /* odd pixels */ ++ nptr+=2; optr+=2; uptr+=2; ++ } ++ *(nptr++)=(((int)*(optr++))+ ++ ((int)*(uptr++))+1)>>1; /* 2nd last pixel */ ++ *(nptr++)=(((int)*(optr++))+ ++ ((int)*(uptr++))+1)>>1; /* last pixel */ ++ } ++ ++ xvbcopy(p + (2*h-2)*mw, /* 2nd last row */ ++ p + (2*h-1)*mw, /* the last row */ ++ 2*w); /* length of a new row */ ++ ++ h*=2; w*=2; ++ mag>>=1; /* Obviously mag must be a power of 2 ! */ ++ } ++} ++ ++/*******************************************/ ++static int ++pcdError(char *fname, char *st) ++{ ++ SetISTR(ISTR_WARNING,"%s: %s", fname, st); ++ return 0; ++} ++ ++ ++/**** Stuff for PCDDialog box ****/ ++ ++#define TWIDE 380 ++#define THIGH 160 ++#define T_NBUTTS 2 ++#define T_BOK 0 ++#define T_BCANC 1 ++#define BUTTH 24 ++ ++static void drawTD PARM((int, int, int, int)); ++static void clickTD PARM((int, int)); ++static void doCmd PARM((int)); ++static void PCDSetParams PARM((void)); ++ ++/* local variables */ ++static BUTT tbut[T_NBUTTS]; ++static RBUTT *resnRB; ++ ++ ++ ++/***************************************************/ ++void CreatePCDW() ++{ ++ int y; ++ ++ pcdW = CreateWindow("xv pcd", "XVpcd", NULL, ++ TWIDE, THIGH, infofg, infobg, 0); ++ if (!pcdW) FatalError("can't create pcd window!"); ++ ++ XSelectInput(theDisp, pcdW, ExposureMask | ButtonPressMask | KeyPressMask); ++ ++ BTCreate(&tbut[T_BOK], pcdW, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH, ++ "Ok", infofg, infobg, hicol, locol); ++ ++ BTCreate(&tbut[T_BCANC], pcdW, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH, ++ "Cancel", infofg, infobg, hicol, locol); ++ ++ y = 55; ++ resnRB = RBCreate(NULL, pcdW, 36, y, "192*128 Base/16", ++ infofg, infobg,hicol,locol); ++ RBCreate(resnRB, pcdW, 36, y+18, "384*256 Base/4", ++ infofg, infobg,hicol,locol); ++ RBCreate(resnRB, pcdW, 36, y+36, "768*512 Base", ++ infofg, infobg, hicol, locol); ++ RBCreate(resnRB, pcdW, TWIDE/2, y, "1536*1024 4Base", ++ infofg, infobg, hicol, locol); ++ RBCreate(resnRB, pcdW, TWIDE/2, y+18, "3072*2048 16Base", ++ infofg, infobg, hicol, locol); ++ ++ CBCreate(&lutCB, pcdW, TWIDE/2, y+36, "Linear LUT", ++ infofg, infobg, hicol, locol); ++ ++ RBSelect(resnRB, 2); ++ ++ XMapSubwindows(theDisp, pcdW); ++} ++ ++ ++/***************************************************/ ++void PCDDialog(vis) ++int vis; ++{ ++ if (vis) { ++ CenterMapWindow(pcdW, tbut[T_BOK].x + tbut[T_BOK].w/2, ++ tbut[T_BOK].y + tbut[T_BOK].h/2, TWIDE, THIGH); ++ } ++ else XUnmapWindow(theDisp, pcdW); ++ pcdUp = vis; ++} ++ ++ ++/***************************************************/ ++int PCDCheckEvent(xev) ++XEvent *xev; ++{ ++ /* check event to see if it's for one of our subwindows. If it is, ++ deal accordingly, and return '1'. Otherwise, return '0' */ ++ ++ int rv; ++ rv = 1; ++ ++ if (!pcdUp) return 0; ++ ++ if (xev->type == Expose) { ++ int x,y,w,h; ++ XExposeEvent *e = (XExposeEvent *) xev; ++ x = e->x; y = e->y; w = e->width; h = e->height; ++ ++ if (e->window == pcdW) drawTD(x, y, w, h); ++ else rv = 0; ++ } ++ ++ else if (xev->type == ButtonPress) { ++ XButtonEvent *e = (XButtonEvent *) xev; ++ int x,y; ++ x = e->x; y = e->y; ++ ++ if (e->button == Button1) { ++ if (e->window == pcdW) clickTD(x,y); ++ else rv = 0; ++ } /* button1 */ ++ else rv = 0; ++ } /* button press */ ++ ++ ++ else if (xev->type == KeyPress) { ++ XKeyEvent *e = (XKeyEvent *) xev; ++ char buf[128]; KeySym ks; XComposeStatus status; ++ int stlen; ++ ++ stlen = XLookupString(e,buf,128,&ks,&status); ++ buf[stlen] = '\0'; ++ ++ RemapKeyCheck(ks, buf, &stlen); ++ ++ if (e->window == pcdW) { ++ if (stlen) { ++ if (buf[0] == '\r' || buf[0] == '\n') { /* enter */ ++ FakeButtonPress(&tbut[T_BOK]); ++ } ++ else if (buf[0] == '\033') { /* ESC */ ++ FakeButtonPress(&tbut[T_BCANC]); ++ } ++ } ++ } ++ else rv = 0; ++ } ++ else rv = 0; ++ ++ if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) { ++ XBell(theDisp, 50); ++ rv = 1; /* eat it */ ++ } ++ ++ return rv; ++} ++ ++ ++/***************************************************/ ++void ++PCDSetParamOptions(char *fname) ++{ ++ int cur; ++ cur = RBWhich(resnRB); ++ ++ RBSetActive(resnRB,0,1); ++ RBSetActive(resnRB,1,1); ++ RBSetActive(resnRB,2,1); ++ RBSetActive(resnRB,3,1); ++ RBSetActive(resnRB,4,1); ++ CBSetActive(&lutCB,1); ++} ++ ++ ++/***************************************************/ ++static void ++drawTD(int x, int y, int w, int h) ++{ ++ char *title = "Load PhotoCD file..."; ++ int i; ++ XRectangle xr; ++ ++ xr.x = x; xr.y = y; xr.width = w; xr.height = h; ++ XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted); ++ ++ XSetForeground(theDisp, theGC, infofg); ++ XSetBackground(theDisp, theGC, infobg); ++ ++ for (i=0; i<T_NBUTTS; i++) BTRedraw(&tbut[i]); ++ ++ ULineString(pcdW, resnRB->x-16, resnRB->y-10-DESCENT, "Resolution"); ++ RBRedraw(resnRB, -1); ++ CBRedraw(&lutCB); ++ ++ XDrawString(theDisp, pcdW, theGC, 20, 19, title, strlen(title)); ++ ++ XSetClipMask(theDisp, theGC, None); ++} ++ ++ ++/***************************************************/ ++static void clickTD(x,y) ++int x,y; ++{ ++ int i; ++ BUTT *bp; ++ ++ /* check BUTTs */ ++ ++ /* check the RBUTTS first, since they don't DO anything */ ++ if ( (i=RBClick(resnRB, x,y)) >= 0) { ++ (void) RBTrack(resnRB, i); ++ return; ++ } ++ ++ if(CBClick(&lutCB, x, y)) { ++ (void) CBTrack(&lutCB); ++ return; ++ } ++ ++ for (i=0; i<T_NBUTTS; i++) { ++ bp = &tbut[i]; ++ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break; ++ } ++ ++ if (i<T_NBUTTS) { /* found one */ ++ if (BTTrack(bp)) doCmd(i); ++ } ++} ++ ++ ++ ++/***************************************************/ ++static void doCmd(cmd) ++int cmd; ++{ ++ leaveitup=0; ++ goforit=0; ++ switch (cmd) { ++ case T_BOK: PCDSetParams(); ++ goforit=1; ++ case T_BCANC: PCDDialog(0); ++ break; ++ ++ default: break; ++ } ++} ++ ++ ++/*******************************************/ ++static void PCDSetParams() ++{ ++ switch (RBWhich(resnRB)) { ++ case 0: size = 0; break; ++ case 1: size = 1; break; ++ case 2: size = 2; break; ++ case 3: size = 3; break; ++ case 4: size = 4; break; ++ case 5: size = 0; break; ++ default: size = 0; break; ++ } ++} ++ ++/* ++ * Read the Huffman tables which consist of an unsigned byte # of entries ++ * (less 1) followed by up to 256 entries, each of which is a series of 4 ++ * unsigned bytes - length, highseq, lowseq, and key. ++ * ++ * Store the huffman table into tree type structure: ++ * ++ * int int[n of entries*2] ++ * ++ * Each entry consists of two words (the 1st for zero and the 2nd for one). ++ * ++ * If the word is negative, then subtract it from the current pointer to ++ * get the next entry (ie. it is the negative offset from the current ++ * position*2 in order to skip entries not words) with which to ++ * make a decision. ++ * ++ * If the word is not negative, then the low 8 bits contain the value (which ++ * is supposed to be a signed char) and the rest of the word is zero. ++ */ ++static void ++dumphufftab(int n, const byte *h, int m, const int *t) ++{ ++ int j; ++ ++ for(j = 0; j < n || j < m; ++j) { ++ if(j < m) ++ fprintf(stderr, "%04x %04x ::", 0xffff & t[2*j + 0], ++ 0xffff & t[2*j + 1]); ++ else ++ fprintf(stderr, "%s %s ::", " ", " "); ++ if(j < n) { ++ int k; ++ unsigned l = (h[4*j + 1] << 8) | h[4*j + 2]; ++ ++ fprintf(stderr, " %02x %2d ", h[4*j + 3], h[4*j + 0]); ++ for(k = 0; k <= h[4*j + 0]; ++k, l *= 2) ++ fprintf(stderr, "%c", '0'+((l & 0x8000) != 0)); ++ } ++ fprintf(stderr, "\n"); ++ } ++} ++ ++static int * ++gethufftable(void) ++{ ++ int *hufftab, *h, i, j, N, num, bufsize, huffptr, hufftop; ++ byte *huf; ++ ++ /* ++ * absorb the entirety of the table in one chunk (for better ++ * dumps in case of error) ++ */ ++ trace((stderr, "hufftab 0x%08lx ", ftell(fp))); ++ num = 1 + fgetc(fp); /* 256 max */ ++ huf = (byte *)alloca(4*num*sizeof(byte)); ++ if((i = fread(huf, 1, 4*num, fp)) != 4*num) { ++ fprintf(stderr, "unexpected EOF: got %d bytes, wanted %d\n", ++ i, 4*num); ++ return NULL; ++ } ++ ++ /* ++ * guess an initial size and prepare the initial entry ++ */ ++ trace((stderr, "length %u\n", num)); ++ N = 2*num; /* 512 max */ ++ bufsize = N * sizeof(int); ++/* this case can't happen, but added for symmetry with loop below ++ if (N/2 != num || bufsize/N != sizeof(int)) { ++ SetISTR(ISTR_WARNING, "Huffman table size out of range"); ++ return NULL; ++ } ++ */ ++ if((hufftab = (int *)malloc(bufsize)) == NULL) ++ FatalError("couldn't malloc initial Huffman table"); ++ hufftab[0] = hufftab[1] = 0; ++ ++ /* ++ * we check the table for reasonableness; there is a lack of detailed ++ * documentation on this format. in particular, for the base16, ++ * the position of the huffman tables is uncertain to within one ++ * "sector", and we have to detect his before trying to read ++ * bogusness. ++ */ ++ hufftop = 0; ++ for(i = 0; i < num; ++i) { ++ unsigned length = huf[4*i + 0], ++ codeword = (huf[4*i + 1] << 8) | huf[4*i + 2]; ++ ++ /* ++ * some sanity checks ++ */ ++ if(length >= 16) { ++ fprintf(stderr, ++ "gethufftable: improbable length @ %d/%d\n", ++ i, num); ++ dumphufftab(num, huf, hufftop/2, hufftab); ++ free(hufftab); ++ return NULL; ++ } ++ ++ /* ++ * walk the whole set of codes ++ */ ++ huffptr = 0; ++ for(j = 0; j < 16; ++j, codeword *= 2) { ++ /* ++ * choose the child node ++ */ ++ if(codeword & 0x8000) ++ ++huffptr; ++ ++ /* ++ * store value at end-of-code ++ */ ++ if(j == length) { ++ /* ++ * more sanity ++ */ ++ if((codeword *= 2) & 0xffff) { ++ fprintf(stderr, ++ "gethufftable: " ++ ":probable invalid code @ %d\n", ++ i); ++ dumphufftab(num, huf, ++ hufftop/2, hufftab); ++ free(hufftab); ++ return NULL; ++ } ++ hufftab[huffptr] = 1 + (int) huf[4*i + 3]; ++ break; ++ } ++ ++ /* ++ * otherwise, follow the tree to date ++ */ ++ if(hufftab[huffptr] < 0) { ++ huffptr -= hufftab[huffptr]; ++ continue; ++ } else if(hufftab[huffptr] > 0) { ++ fprintf(stderr, "duplicate code %d %d/%d\n", ++ huffptr, i, num); ++ dumphufftab(num, huf, hufftop/2, hufftab); ++ free(hufftab); ++ return NULL; ++ } ++ ++ /* ++ * and if necessary, make the tree bigger ++ */ ++ if((hufftop += 2) >= N) { ++ int oldN = N; ++#if TRACE ++ dumphufftab(num, huf, hufftop/2, hufftab); ++#endif ++ N *= 2; ++ bufsize = N*sizeof(int); ++ if (N/2 != oldN || bufsize/N != sizeof(int)) { ++ SetISTR(ISTR_WARNING, ++ "new Huffman table is too large"); ++ free(hufftab); ++ return NULL; ++ } ++ h = (int *)realloc(hufftab, bufsize); ++ if(h == NULL) { ++ fprintf(stderr, ++ "Table overflow %d/%d\n", ++ i, num); ++ dumphufftab(num, huf, ++ hufftop/2, hufftab); ++ free(hufftab); ++ FatalError( ++ "couldn't realloc Huffman table"); ++ } ++ hufftab = h; ++ } ++ ++ /* ++ * then add new ptr ++ */ ++ hufftab[huffptr] = huffptr - hufftop; ++ huffptr = hufftop; ++ hufftab[huffptr + 0] = ++ hufftab[huffptr + 1] = 0; ++ } ++ } ++ return hufftab; ++} ++ ++/* WORDTYPE & char buffer must be unsigned else */ ++/* fills with sign bit not 0 on right shifts */ ++typedef unsigned int WORDTYPE; ++typedef int SWORDTYPE; ++#define WORDSIZE sizeof(WORDTYPE) ++#define NBYTESINBUF 0x800 ++ ++static byte buffer[NBYTESINBUF]; ++static int bitsleft=0; ++static int bytesleft=0; ++static byte *bufptr; ++static WORDTYPE word; ++ ++#if 0 ++static void ++dumpbuffer(void) ++{ ++ int i,left; ++ byte *ptr=buffer; ++ ++ fprintf(stderr,"dumpbuffer: bytesleft=%d bitsleft= %d word=0x%08lx\n", ++ bytesleft,bitsleft,(unsigned long)word); ++ for (left=NBYTESINBUF; left>0; left-=16) { ++ fprintf(stderr,"%05d ",left); ++ for (i=0; i<8; i++) { ++ fprintf(stderr,"%02x",*ptr++); ++ fprintf(stderr,"%02x ",*ptr++); ++ } ++ fprintf(stderr,"\n"); ++ } ++} ++#endif /* 0 */ ++ ++static void ++loadbuffer(void) ++{ ++ if ((bytesleft=fread(buffer,1,NBYTESINBUF,fp)) == 0) { ++ fprintf(stderr,"Truncation error\n"); ++ exit(1); ++ } ++ bufptr=buffer; ++ /* dumpbuffer(); */ ++} ++ ++static void ++loadbyte(void) ++{ ++ if (bytesleft <= 0) loadbuffer(); ++ --bytesleft; ++ word|=(WORDTYPE)(*bufptr++)<<(sizeof(WORDTYPE)*8-8-bitsleft); ++ bitsleft+=8; ++} ++ ++static int ++getbit(void) ++{ ++ int bit; ++ ++ while (bitsleft <= 0) loadbyte(); ++ --bitsleft; ++ bit=(SWORDTYPE)(word)<0; /* assumes word is signed */ ++ /* bit=word>>(sizeof(WORDTYPE)*8-1); */ ++ word<<=1; ++ return bit; ++} ++ ++static WORDTYPE ++getnn(int nn) ++{ ++ WORDTYPE value; ++ ++ while (bitsleft <= nn) loadbyte(); ++ bitsleft-=nn; ++ value=word>>(sizeof(WORDTYPE)*8-nn); ++ word<<=nn; ++ return value; ++} ++ ++static WORDTYPE ++isnn(int nn) ++{ ++ WORDTYPE value; ++ ++ while (bitsleft <= nn) loadbyte(); ++ value=word>>(sizeof(WORDTYPE)*8-nn); ++ return value; ++} ++ ++static void ++skipnn(int nn) ++{ ++ while (bitsleft <= nn) loadbyte(); ++ bitsleft-=nn; ++ word<<=nn; ++} ++ ++#define get1() (getbit()) ++#define get2() (getnn(2)) ++#define get8() (getnn(8)) ++#define get13() (getnn(13)) ++#define get16() (getnn(16)) ++#define get24() (getnn(24)) ++ ++#define is24() (isnn(24)) ++ ++#define skip1() (skipnn(1)) ++#define skip24() (skipnn(24)) ++ ++static int ++gethuffdata( byte *luma, ++ byte *chroma1, ++ byte *chroma2, ++ int realrowwidth, ++ int maxrownumber) ++{ ++static byte clip[3*256]; ++ int *hufftable[3], *huffstart = NULL, *huffptr = NULL; ++ int row, col, plane, i, result = 1; ++#if TRACE ++ int uflow = 0, oflow = 0; ++#endif ++ byte *pixelptr = NULL; ++ ++ trace((stderr,"gethuffdata: start @ 0x%08lx (sector %ld.%ld)\n", ++ ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800)); ++ ++ /* ++ * correction clipping ++ */ ++ if(clip[256+255] == 0) { ++ for(i = 0; i < 256; ++i) ++ clip[i + 0] = 0x00, ++ clip[i + 256] = (byte) i, ++ clip[i + 512] = 0xff; ++ } ++ ++ /* ++ * should really only look for luma plane for 4base, but the ++ * there are zeroes in the rest of the sector that give both ++ * chroma tables 0 length ++ */ ++ for(i = 0; i < 3; ++i) ++ hufftable[i] = NULL; ++ for(i = 0; i < 3; ++i) { ++ if((hufftable[i] = gethufftable()) == NULL) { ++ result = 0; ++ break; ++ } ++ } ++ if(result == 0) ++ goto oops; ++ ++ /* ++ * skip remainder of current sector ++ */ ++ i = (ftell(fp) | 0x7ff) + 1; ++ if(fseek(fp, i, SEEK_SET) < 0) { ++ fprintf(stderr, "gethuffdata: sector skip failed\n"); ++ return 0; ++ } ++ ++ /* ++ * skip remainder of "sector" ++ */ ++ i = 0; ++ while (is24() != 0xfffffe) { ++ (void)get24(); ++ if(++i == 1) ++ trace((stderr,"gethuffdata: skipping for sync ...")); ++ } ++ if(i != 0) ++ trace((stderr, " %d times\n", i)); ++ ++ while(result) { ++ if(is24() == 0xfffffe) { ++ skip24(); ++ plane = get2(); ++ row = get13(); col = 0; ++ skip1(); ++ if(row >= maxrownumber) { ++ trace((stderr, ++ "gethuffdata: stopping at row %d\n", ++ row)); ++ break; ++ } ++ switch (plane) { ++ case 0: ++ huffstart = hufftable[0]; ++ pixelptr = luma + row*realrowwidth; ++ break; ++ ++ case 2: ++ huffstart = hufftable[1]; ++ pixelptr = chroma1 + row/2*realrowwidth/2; ++ break; ++ ++ case 3: ++ huffstart = hufftable[2]; ++ pixelptr = chroma2 + row/2*realrowwidth/2; ++ break; ++ ++ default: ++ fprintf(stderr, "gethuffdata: bad plane %d\n", ++ plane); ++ result = 0; ++ break; ++ } ++ WaitCursor(); ++ continue; ++ } ++ ++ /* ++ * locate correction in huffman tree ++ */ ++ for(huffptr = huffstart;;) { ++ huffptr += get1(); ++ if(*huffptr < 0) { ++ huffptr -= *huffptr; ++ } else if(*huffptr == 0) { ++ fprintf(stderr, ++ "gethuffdata: invalid code: " ++ "image quality reduced\n"); ++ result = 0; ++ break; ++ } else ++ break; ++ } ++ if(!result) ++ break; ++ ++ /* ++ * apply correction to the pixel ++ * ++ * eeeek!! the corrections can sometimes over or underflow! ++ * this strongly suggested that the 'magnify' method was in ++ * some way wrong. however, experiments showed that the ++ * over/under flows even occured for the pixels that are ++ * copied through magnify without change (ie, the even ++ * row/even column case). curiously, though, the odd ++ * column and odd row cases were about 3x more likely to have ++ * the over/underflow, and the odd row/odd column case was ++ * about 5x higher, so maybe the use of a bi-linear ++ * interpolation is not correct -- just *close*? ++ * ++ * the other clue in this area is that the overflows are ++ * by far most frequenct along edges of very bright ++ * areas -- rarely in the interior of such regions. ++ */ ++ i = (int) *pixelptr + (signed char) (*huffptr - 1); ++#if TRACE ++ if(i > 255) ++ ++oflow; ++/* trace((stderr, ++ "gethuffdata: oflow %d %d %d\n", row, col, i));*/ ++ else if(i < 0) ++ ++uflow; ++/* trace((stderr, ++ "gethuffdata: uflow %d %d %d\n", row, col, i));*/ ++ ++col; ++#endif ++ *pixelptr++ = clip[i + 256]; ++ } ++ ++oops: ++ for(i = 0; i < 3; ++i) ++ free(hufftable[i]); ++ trace((stderr, "gethuffdata: uflow=%d oflow=%d\n", uflow, oflow)); ++ trace((stderr, "gethuffdata: done @ 0x%08lx (sector %ld.%d)\n", ++ ftell(fp), ftell(fp)/0x800, 0x800 - bytesleft)); ++ return result; ++} ++ ++#endif /* HAVE_PCD */ +diff -ruN xv-3.10a-bugfixes/xvpds.c xv-3.10a-enhancements/xvpds.c +--- xv-3.10a-bugfixes/xvpds.c 2005-04-03 11:31:30.000000000 -0700 ++++ xv-3.10a-enhancements/xvpds.c 2005-04-17 21:40:40.000000000 -0700 +@@ -77,8 +77,7 @@ + * Huffman-encoded, and the encoding histogram follows the ASCII headers. + * To decode these, we use a slightly modified version of "vdcomp.c" from the + * NASA Viking CD-ROMS. For xv to work, you need to have vdcomp compiled +- * and in your search path. vdcomp.c should be included with this +-distribution. ++ * and in your search path. vdcomp.c should be included with this distribution. + * + * I've heard that newer discs have FITS images on them. If they do, support + * for them will be added when I get one. Until then, you can use fitstopgm. +@@ -102,7 +101,7 @@ + * This software is provided "as is" without any express or implied warranty. + */ + +- ++#define NEEDSDIR /* for S_IRUSR|S_IWUSR */ + #include "xv.h" + + #ifdef HAVE_PDS +@@ -129,27 +128,32 @@ + + /* This is arbitrary. Everything I've seen so far fits in 50 chars */ + #define COMMENTSIZE 50 ++#define INOTESIZE 1000 + + + static int lastwasinote = FALSE; +-static char scanbuff [MAX_SIZE], +- rtbuff [RTBUFFSIZE], +- inote [20*COMMENTSIZE], +- infobuff [COMMENTSIZE], +- spacecraft [COMMENTSIZE], +- target [COMMENTSIZE], +- filtname [COMMENTSIZE], +- gainmode [COMMENTSIZE], +- editmode [COMMENTSIZE], +- scanmode [COMMENTSIZE], +- exposure [COMMENTSIZE], +- shuttermode [COMMENTSIZE], +- mphase [COMMENTSIZE], +- iname [COMMENTSIZE], +- itime [COMMENTSIZE], +- garbage [1020], ++static char scanbuff [MAX_SIZE+1], ++ rtbuff [RTBUFFSIZE+1], ++ inote [INOTESIZE+1], ++ infobuff [COMMENTSIZE+1], ++ spacecraft [COMMENTSIZE+1], ++ target [COMMENTSIZE+1], ++ filtname [COMMENTSIZE+1], ++ gainmode [COMMENTSIZE+1], ++ editmode [COMMENTSIZE+1], ++ scanmode [COMMENTSIZE+1], ++ exposure [COMMENTSIZE+1], ++ shuttermode [COMMENTSIZE+1], ++ mphase [COMMENTSIZE+1], ++ iname [COMMENTSIZE+1], ++ itime [COMMENTSIZE+1], ++ garbage [1024], + *tmptmp, + pdsuncompfname[FNAMESIZE]; ++ ++#define SSTR(l) "%" #l "s" ++#define S(l) SSTR(l) ++ + byte *image; + static int elaphe; + +@@ -251,6 +255,9 @@ + /* returns '1' on success, '0' on failure */ + + int tempnum, bytewidth, bufsize; ++#ifndef USE_MKSTEMP ++ int tmpfd; ++#endif + FILE *zf; + static int isfixed,teco,i,j,itype,vaxbyte, + recsize,hrecsize,irecsize,isimage,labelrecs,labelsofar, +@@ -397,7 +404,7 @@ + + if (strcmp(scanbuff,"END") == 0) { + break; +- } else if (sscanf(scanbuff," RECORD_TYPE = %s",rtbuff) == 1) { ++ } else if (sscanf(scanbuff, " RECORD_TYPE = " S(RTBUFFSIZE), rtbuff) == 1) { + if (strncmp(rtbuff,"VARIABLE_LENGTH", (size_t) 15) == 0) { + /* itype=PDSVARIABLE; */ + } else if (strncmp(rtbuff,"FIXED_LENGTH", (size_t) 12) == 0) { +@@ -416,7 +423,7 @@ + if (irecsize == 0) irecsize=recsize; + lastwasinote=FALSE; + continue; +- } else if (sscanf(scanbuff," FILE_TYPE = %s", rtbuff) != 0) { ++ } else if (sscanf(scanbuff, " FILE_TYPE = " S(RTBUFFSIZE), rtbuff) != 0) { + lastwasinote=FALSE; + if (strncmp(rtbuff,"IMAGE", (size_t) 5) == 0) { + isimage=TRUE; +@@ -445,74 +452,74 @@ + lastwasinote=FALSE; continue; + } else if (sscanf(scanbuff," SAMPLE_BITS = %d", &samplesize) == 1) { + lastwasinote=FALSE; continue; +- } else if (sscanf(scanbuff," SAMPLE_TYPE = %s", sampletype) == 1) { ++ } else if (sscanf(scanbuff, " SAMPLE_TYPE = " S(64), sampletype) == 1) { + lastwasinote=FALSE; continue; +- } else if (sscanf(scanbuff," SPACECRAFT_NAME = %s %s", ++ } else if (sscanf(scanbuff," SPACECRAFT_NAME = " S(COMMENTSIZE) " " S(1023), + spacecraft,garbage) == 2 ) { +- strcat(spacecraft,xv_strstr(scanbuff, spacecraft)+strlen(spacecraft)); ++ const char *tmp = xv_strstr(scanbuff, spacecraft) + strlen(spacecraft); ++ strncat(spacecraft, tmp, COMMENTSIZE - strlen(spacecraft)); + lastwasinote=FALSE; continue; +- } else if (sscanf(scanbuff," SPACECRAFT_NAME = %s", spacecraft) == 1) { ++ } else if (sscanf(scanbuff, " SPACECRAFT_NAME = " S(COMMENTSIZE), spacecraft) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," TARGET_NAME = %s", target) == 1) { ++ } else if (sscanf(scanbuff, " TARGET_NAME = " S(COMMENTSIZE), target) == 1) { + lastwasinote=FALSE; continue; +- } else if (sscanf(scanbuff," TARGET_BODY = %s", target) == 1) { ++ } else if (sscanf(scanbuff, " TARGET_BODY = " S(COMMENTSIZE), target) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," MISSION_PHASE_NAME = %s", mphase) == 1) { ++ } else if (sscanf(scanbuff, " MISSION_PHASE_NAME = " S(COMMENTSIZE), mphase) == 1) { + lastwasinote=FALSE; continue; +- } else if (sscanf(scanbuff," MISSION_PHASE = %s", mphase) == 1) { ++ } else if (sscanf(scanbuff, " MISSION_PHASE = " S(COMMENTSIZE), mphase) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," INSTRUMENT_NAME = %s", iname) == 1) { ++ } else if (sscanf(scanbuff, " INSTRUMENT_NAME = " S(COMMENTSIZE), iname) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," GAIN_MODE_ID = %s", gainmode) == 1) { ++ } else if (sscanf(scanbuff, " GAIN_MODE_ID = " S(COMMENTSIZE), gainmode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," INSTRUMENT_GAIN_STATE = %s",gainmode)==1) { ++ } else if (sscanf(scanbuff, " INSTRUMENT_GAIN_STATE = " S(COMMENTSIZE), gainmode) ==1 ) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," EDIT_MODE_ID = %s", editmode) == 1) { ++ } else if (sscanf(scanbuff, " EDIT_MODE_ID = " S(COMMENTSIZE), editmode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," INSTRUMENT_EDIT_MODE = %s", editmode)==1) { ++ } else if (sscanf(scanbuff, " INSTRUMENT_EDIT_MODE = " S(COMMENTSIZE), editmode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," SCAN_MODE_ID = %s", scanmode) == 1) { ++ } else if (sscanf(scanbuff, " SCAN_MODE_ID = " S(COMMENTSIZE), scanmode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," INSTRUMENT_SCAN_RATE = %s", scanmode)==1) { ++ } else if (sscanf(scanbuff, " INSTRUMENT_SCAN_RATE = " S(COMMENTSIZE), scanmode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," SHUTTER_MODE_ID = %s", shuttermode) == 1) { ++ } else if (sscanf(scanbuff, " SHUTTER_MODE_ID = " S(COMMENTSIZE), shuttermode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," INSTRUMENT_SHUTTER_MODE = %s", +- shuttermode) == 1) { ++ } else if (sscanf(scanbuff, " INSTRUMENT_SHUTTER_MODE = " S(COMMENTSIZE), shuttermode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," SCAN_MODE_ID = %s", scanmode) == 1) { ++ } else if (sscanf(scanbuff, " SCAN_MODE_ID = " S(COMMENTSIZE), scanmode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," INSTRUMENT_SCAN_RATE = %s", scanmode)==1) { ++ } else if (sscanf(scanbuff, " INSTRUMENT_SCAN_RATE = " S(COMMENTSIZE), scanmode) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," SPACECRAFT_EVENT_TIME = %s", itime) == 1) { ++ } else if (sscanf(scanbuff, " SPACECRAFT_EVENT_TIME = " S(COMMENTSIZE), itime) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," IMAGE_TIME = %s", itime) == 1) { ++ } else if (sscanf(scanbuff, " IMAGE_TIME = " S(COMMENTSIZE), itime) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," FILTER_NAME = %s", filtname) == 1) { ++ } else if (sscanf(scanbuff, " FILTER_NAME = " S(COMMENTSIZE), filtname) == 1) { + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff," INSTRUMENT_FILTER_NAME = %s",filtname)==1) { ++ } else if (sscanf(scanbuff, " INSTRUMENT_FILTER_NAME = " S(COMMENTSIZE), filtname) == 1) { + lastwasinote=FALSE; continue; + +- } else if ((sscanf(scanbuff," EXPOSURE_DURATION = %s", exposure) == 1) +- || (sscanf(scanbuff," INSTRUMENT_EXPOSURE_DURATION = %s", +- exposure) == 1)) { ++ } else if ((sscanf(scanbuff, " EXPOSURE_DURATION = " S(COMMENTSIZE), exposure) == 1) ++ || (sscanf(scanbuff, " INSTRUMENT_EXPOSURE_DURATION = " S(COMMENTSIZE), ++ exposure)) == 1) { + tmptmp = (char *) index(scanbuff,'='); + tmptmp++; + while((*tmptmp) == ' ') +@@ -520,10 +527,10 @@ + strcpy(exposure,tmptmp); + lastwasinote=FALSE; continue; + +- } else if (sscanf(scanbuff, "NOTE = %s", inote) == 1) { ++ } else if (sscanf(scanbuff, "NOTE = " S(INOTESIZE), inote) == 1) { + tmptmp = (char *) index(scanbuff,'='); tmptmp++; + while (((*tmptmp) == ' ') || ((*tmptmp) == '"')) tmptmp++; +- strcpy(inote,tmptmp); ++ strncpy(inote, tmptmp, INOTESIZE - 1); + strcat(inote," "); + + /* evil and somewhat risky: A "note" (really, any textual +@@ -548,7 +555,7 @@ + } else if (lastwasinote) { + tmptmp=scanbuff; + while (((*tmptmp) == ' ') || ((*tmptmp) == '"')) tmptmp++; +- strcat(inote,tmptmp); ++ strncat(inote, tmptmp, INOTESIZE - strlen(inote) - 1); + strcat(inote," "); + if (index(tmptmp,'"') != NULL) + lastwasinote=FALSE; +@@ -647,27 +654,27 @@ + + *infobuff='\0'; + if (*spacecraft) { +- strcat(infobuff,spacecraft); ++ strncat(infobuff, spacecraft, sizeof(infobuff) - 1); + } + + if (*target) { +- strcat(infobuff,", "); +- strcat(infobuff,target); ++ strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1); ++ strncat(infobuff, target, sizeof(infobuff) - strlen(infobuff) - 1); + } + + if (*filtname) { +- strcat(infobuff,", "); +- strcat(infobuff,filtname); ++ strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1); ++ strncat(infobuff, filtname, sizeof(infobuff) - strlen(infobuff) - 1); + } + + if (*itime) { +- strcat(infobuff,", "); +- strcat(infobuff,itime); ++ strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1); ++ strncat(infobuff, itime, sizeof(infobuff) - strlen(infobuff) - 1); + } + +- SetISTR(ISTR_WARNING,infobuff); ++ SetISTR(ISTR_WARNING, "%s", infobuff); + +- strcpy(pdsuncompfname,fname); ++ strncpy(pdsuncompfname,fname,sizeof(pdsuncompfname) - 1); + ftypstr = ""; + + switch (itype) { +@@ -695,7 +702,7 @@ + fclose(zf); + + #ifndef VMS +- sprintf(pdsuncompfname,"%s/xvhuffXXXXXX", tmpdir); ++ snprintf(pdsuncompfname, sizeof(pdsuncompfname) - 1, "%s/xvhuffXXXXXX", tmpdir); + #else + strcpy(pdsuncompfname,"sys$disk:[]xvhuffXXXXXX"); + #endif +@@ -704,10 +711,16 @@ + close(mkstemp(pdsuncompfname)); + #else + mktemp(pdsuncompfname); ++ tmpfd = open(pdsuncompfname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR); ++ if (tmpfd < 0) { ++ SetISTR(ISTR_WARNING,"Unable to create temporary file."); ++ return 0; ++ } ++ close(tmpfd); + #endif + + #ifndef VMS +- sprintf(scanbuff,"%s %s - 4 >%s",PDSUNCOMP,fname,pdsuncompfname); ++ sprintf(scanbuff,"%s '%s' - 4 > %s", PDSUNCOMP, fname, pdsuncompfname); + #else + sprintf(scanbuff,"%s %s %s 4",PDSUNCOMP,fname,pdsuncompfname); + #endif +@@ -823,26 +836,26 @@ + char tmp[256]; + *(pinfo->comment) = '\0'; + +- sprintf(tmp, "Spacecraft: %-28sTarget: %-32s\n", spacecraft, target); +- strcat(pinfo->comment, tmp); ++ sprintf(tmp, "Spacecraft: %-28.28sTarget: %-32.32s\n", spacecraft, target); ++ strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1); + +- sprintf(tmp, "Filter: %-32sMission phase: %-24s\n", filtname, mphase); +- strcat(pinfo->comment, tmp); ++ sprintf(tmp, "Filter: %-32.32sMission phase: %-24.24s\n", filtname, mphase); ++ strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1); + +- sprintf(tmp, "Image time: %-28sGain mode: %-29s\n", itime, gainmode); +- strcat(pinfo->comment, tmp); ++ sprintf(tmp, "Image time: %-28.28sGain mode: %-29.29s\n", itime, gainmode); ++ strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1); + +- sprintf(tmp, "Edit mode: %-29sScan mode: %-29s\n", editmode, scanmode); +- strcat(pinfo->comment, tmp); ++ sprintf(tmp, "Edit mode: %-29.29sScan mode: %-29.29s\n", editmode, scanmode); ++ strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1); + +- sprintf(tmp, "Exposure: %-30sShutter mode: %-25s\n", exposure,shuttermode); +- strcat(pinfo->comment, tmp); ++ sprintf(tmp, "Exposure: %-30.30sShutter mode: %-25.25s\n", exposure,shuttermode); ++ strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1); + +- sprintf(tmp, "Instrument: %-28sImage time: %-28s\n", iname, itime); +- strcat(pinfo->comment, tmp); ++ sprintf(tmp, "Instrument: %-28.28sImage time: %-28.28s\n", iname, itime); ++ strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1); + +- sprintf(tmp, "Image Note: %-28s", inote); +- strcat(pinfo->comment, tmp); ++ sprintf(tmp, "Image Note: %-28.28s", inote); ++ strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1); + } + + if (LoadPDSPalette(fname, pinfo)) return 1; +diff -ruN xv-3.10a-bugfixes/xvpi.c xv-3.10a-enhancements/xvpi.c +--- xv-3.10a-bugfixes/xvpi.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvpi.c 2005-04-17 22:57:04.000000000 -0700 +@@ -0,0 +1,1060 @@ ++/* ++ * xvpi.c - load routine for `Pi' format pictures. ++ * ++ * The `Pi' format is made by Yanagisawa. ++ * It is common among many Japanese personal computer users. ++ * ++ */ ++ ++#include "xv.h" ++#include <setjmp.h> ++ ++#ifdef HAVE_PI ++ ++typedef unsigned short data16; ++typedef unsigned int data32; ++ ++struct pi_info { ++ jmp_buf jmp; ++ FILE *fp; ++ struct { ++ int rest; ++ byte cur; ++ }bs; ++ long fsize; ++ byte mode; ++ int width, height; ++ float aspect; ++ int cbits; ++ int numcols; ++ byte *cmap; ++ struct ct_t{ ++ struct elt_t *top; ++ struct elt_t{ ++ struct elt_t *old, *recent; ++ byte val; ++ } *elt; ++ }*ct; ++ int defcmap; ++ int writing_grey; ++}; ++ ++static void pi_open_file PARM((struct pi_info*, char*)); ++static void pi_read_header PARM((struct pi_info*, char**)); ++static void pi_check_id PARM((struct pi_info*)); ++static void pi_read_comment PARM((struct pi_info*, char**)); ++static void pi_read_palette PARM((struct pi_info*)); ++static void pi_expand PARM((struct pi_info*, byte**)); ++static byte pi_read_color PARM((struct pi_info*, int)); ++static int pi_read_position PARM((struct pi_info*)); ++static data32 pi_read_length PARM((struct pi_info*)); ++static int pi_copy_pixels PARM((struct pi_info*, ++ byte*, int, int, data32)); ++ ++static void pi_write_header PARM((struct pi_info*, ++ char*, byte*, byte*, byte*)); ++static void pi_write_id PARM((struct pi_info*)); ++static void pi_write_comment PARM((struct pi_info*, char*)); ++static void pi_write_palette PARM((struct pi_info*, byte*, byte*, byte*)); ++static void pi_compress PARM((struct pi_info*, byte*)); ++static void pi_write_gabage PARM((struct pi_info*)); ++static void pi_write_color PARM((struct pi_info*, int, int)); ++static int pi_test_matching PARM((struct pi_info*, ++ byte*, int, int, data32*)); ++static void pi_write_position PARM((struct pi_info*, int)); ++static void pi_write_length PARM((struct pi_info*, data32)); ++ ++static void pi_table_create PARM((struct pi_info*)); ++static byte pi_table_get_value PARM((struct pi_info*, int, int)); ++static int pi_table_lookup_value PARM((struct pi_info*, int, int)); ++static data32 pi_read_bits PARM((struct pi_info*, int)); ++static void pi_write_bits PARM((struct pi_info*, data32, int)); ++static void pi_init_pi_info PARM((struct pi_info*)); ++static void pi_cleanup_pi_info PARM((struct pi_info*, int)); ++static void pi_cleanup_pinfo PARM((PICINFO*)); ++static void pi_memory_error PARM((char*, char*)); ++static void pi_error PARM((struct pi_info*, int)); ++static void pi_file_error PARM((struct pi_info*, int)); ++static void pi_file_warning PARM((struct pi_info*, int)); ++static void pi_show_pi_info PARM((struct pi_info*)); ++static void *pi_malloc PARM((size_t, char*)); ++static void *pi_realloc PARM((void*, size_t, char*)); ++ ++ ++static char *pi_id = "Pi"; ++static char *pi_msgs[] = { ++ NULL, ++#define PI_OPEN 1 ++ "couldn't open.", ++#define PI_CORRUPT 2 ++ "file corrupted.", ++#define PI_FORMAT 3 ++ "not PI format.", ++#define PI_PLANES 4 ++ "bad number of planes.", ++#define PI_WRITE 5 ++ "write failed.", ++}; ++ ++ ++/* The main routine of `Pi' loader. */ ++int LoadPi(fname, pinfo) ++ char *fname; ++ PICINFO *pinfo; ++{ ++ struct pi_info pi; ++ int e; ++ int i; ++ if(DEBUG) fputs("LoadPi:\n", stderr); ++ ++ pinfo->comment = NULL; ++ pi_init_pi_info(&pi); ++ if((e = setjmp(pi.jmp)) != 0){ ++ /* When an error occurs, comes here. */ ++ pi_cleanup_pi_info(&pi, 0); ++ pi_cleanup_pinfo(pinfo); ++ if(DEBUG) fputs("\n", stderr); ++ return 0; ++ } ++ ++ pi_open_file(&pi, fname); ++ pi_read_header(&pi, &pinfo->comment); ++ pi_expand(&pi, &pinfo->pic); ++ ++ pinfo->normw = pinfo->w = pi.width; ++ pinfo->normh = pinfo->h = pi.height; ++ pinfo->type = PIC8; ++ if(pi.numcols > 256) /* shouldn't happen. */ ++ pi.numcols = 256; ++ for(i = 0; i < pi.numcols; i++){ ++ pinfo->r[i] = pi.cmap[i * 3 ]; ++ pinfo->g[i] = pi.cmap[i * 3 + 1]; ++ pinfo->b[i] = pi.cmap[i * 3 + 2]; ++ } ++ pinfo->frmType = F_PI; ++ pinfo->colType = F_FULLCOLOR; ++ sprintf(pinfo->fullInfo, "Pi, %d colors (%ld bytes)", ++ pi.numcols, pi.fsize); ++ sprintf(pinfo->shrtInfo, "%dx%d Pi.", pi.width, pi.height); ++ normaspect = pi.aspect; ++ ++ pi_cleanup_pi_info(&pi, 0); ++ if(DEBUG) fputs("\n", stderr); ++ return 1; ++} ++ ++static void pi_open_file(pi, fname) ++ struct pi_info *pi; ++ char *fname; ++{ ++ if((pi->fp = fopen(fname, "rb")) == NULL) ++ pi_file_error(pi, PI_OPEN); ++ fseek(pi->fp, (size_t) 0, SEEK_END); ++ pi->fsize = ftell(pi->fp); ++ fseek(pi->fp, (size_t) 0, SEEK_SET); ++} ++ ++static void pi_read_header(pi, comm) ++ struct pi_info *pi; ++ char **comm; ++{ ++ byte buf[10]; ++ int mda; ++ int i; ++ ++ pi_check_id(pi); ++ pi_read_comment(pi, comm); ++ ++ if(fread(buf, (size_t) 10, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_CORRUPT); ++ ++ pi->mode = buf[0]; ++ pi->defcmap = pi->mode & 0x80; ++ if(buf[1] != 0 && buf[2] != 0) ++ pi->aspect = (float) buf[2] / (int) buf[1]; ++ pi->cbits = buf[3]; ++ pi->numcols = 1 << pi->cbits; ++ ++ if(pi->cbits != 4 && pi->cbits != 8) ++ pi_error(pi, PI_PLANES); ++ ++ mda = (int) buf[8] << 8 | (int) buf[9]; ++ for(i = 0; i < mda; i++){ ++ if(fgetc(pi->fp) == EOF) ++ pi_file_error(pi, PI_CORRUPT); ++ } ++ ++ if(fread(buf, (size_t) 4, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_CORRUPT); ++ pi->width = (int) buf[0] << 8 | (int) buf[1]; ++ pi->height = (int) buf[2] << 8 | (int) buf[3]; ++ ++ pi_read_palette(pi); ++ ++ if(DEBUG) pi_show_pi_info(pi); ++} ++ ++static void pi_check_id(pi) ++ struct pi_info *pi; ++{ ++ char buf[2]; ++ ++ if(fread(buf, (size_t) 2, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_CORRUPT); ++ if(strncmp(buf, pi_id, (size_t) 2) != 0) ++ pi_error(pi, PI_FORMAT); ++} ++ ++static void pi_read_comment(pi, comm) ++ struct pi_info *pi; ++ char **comm; ++{ ++/* ++ * The comment format is like: ++ * comment string `^Z' dummy string `\0' ++ */ ++ int max = -1, i = 0; ++ int c; ++ ++ while(1){ ++ if((c = fgetc(pi->fp)) == EOF) ++ pi_file_error(pi, PI_CORRUPT); ++ if(c == '\032') /* 0x1a, '^Z' */ ++ break; ++ if(max < i){ ++ max += 32; ++ *comm = pi_realloc(*comm, (size_t) max + 1, "pi_read_comment(1)"); ++ } ++ (*comm)[i++] = c; ++ } ++ if(max < i){ ++ max++; ++ *comm = pi_realloc(*comm, (size_t) max + 1, "pi_read_comment(2)"); ++ } ++ (*comm)[i] = '\0'; ++ ++ while((c = fgetc(pi->fp)) != '\0'){ /* skip the dummy area */ ++ if(c == EOF) ++ pi_file_error(pi, PI_CORRUPT); ++ } ++} ++ ++static void pi_read_palette(pi) ++ struct pi_info *pi; ++{ ++ pi->cmap = pi_malloc((size_t) pi->numcols * 3, "pi_read_palette"); ++ if(pi->mode & 0x80){ ++ if(pi->numcols == 16){ ++ int i; ++ byte on; ++ ++ on = 0x77; ++ for(i = 0; i < 8; i++){ ++ pi->cmap[i * 3 ] = i & 2 ? on : 0; ++ pi->cmap[i * 3 + 1] = i & 4 ? on : 0; ++ pi->cmap[i * 3 + 2] = i & 1 ? on : 0; ++ } ++ on = 0xff; ++ for(; i < 16; i++){ ++ pi->cmap[i * 3 ] = i & 2 ? on : 0; ++ pi->cmap[i * 3 + 1] = i & 4 ? on : 0; ++ pi->cmap[i * 3 + 2] = i & 1 ? on : 0; ++ } ++ }else{ /* pi->numcols == 256 */ ++ int i; ++ byte r, g, b; ++ r = g = b = 0; ++ for(i = 0; i < 256; i++){ ++ pi->cmap[i * 3 ] = r; ++ pi->cmap[i * 3 + 1] = g; ++ pi->cmap[i * 3 + 2] = b; ++ if((b += 0x40) == 0){ ++ if((r += 0x20) == 0) ++ g += 0x20; ++ } ++ } ++ } ++ }else{ ++ if(fread(pi->cmap, (size_t) pi->numcols * 3, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_CORRUPT); ++ } ++} ++ ++/* The main routine to expand `Pi' file. */ ++static void pi_expand(pi, pic) ++ struct pi_info *pi; ++ byte **pic; ++{ ++ byte prev_col = 0; ++ int prev_pos = -1; ++ int cnt = 0, max_cnt = pi->width * pi->height; ++ ++ *pic = pi_malloc((size_t) max_cnt, "pi_expand"); // GRR POSSIBLE OVERFLOW / FIXME ++ ++ pi_table_create(pi); ++ ++ if(pi->width > 2){ ++ (*pic)[0] = pi_read_color(pi, 0); ++ (*pic)[1] = pi_read_color(pi, (*pic)[0]); ++ ++ while(cnt < max_cnt){ ++ int pos = pi_read_position(pi); ++ if(pos != prev_pos){ ++ data32 len = pi_read_length(pi); ++ cnt = pi_copy_pixels(pi, *pic, cnt, pos, len); ++ prev_col = (*pic)[cnt - 1]; ++ prev_pos = pos; ++ }else{ ++ do{ ++ prev_col = pi_read_color(pi, (int) prev_col); ++ (*pic)[cnt++] = prev_col; ++ prev_col = pi_read_color(pi, (int) prev_col); ++ (*pic)[cnt++] = prev_col; ++ }while(pi_read_bits(pi, 1) == 1); ++ ++ prev_pos = -1; ++ } ++ } ++ }else{ ++ while(cnt < max_cnt){ ++ prev_col = pi_read_color(pi, (int) prev_col); ++ (*pic)[cnt++] = prev_col; ++ } ++ } ++} ++ ++static byte pi_read_color(pi, prev) ++ struct pi_info *pi; ++ int prev; ++{ ++ byte n; ++ if(pi->cbits == 4){ ++ if(pi_read_bits(pi, 1) == 1) ++ n = pi_read_bits(pi, 1); /* 1x */ ++ else{ ++ if(pi_read_bits(pi, 1) == 0) ++ n = pi_read_bits(pi, 1) + 2; /* 00x */ ++ else{ ++ if(pi_read_bits(pi, 1) == 0) ++ n = pi_read_bits(pi, 2) + 4; /* 010xx */ ++ else ++ n = pi_read_bits(pi, 3) + 8; /* 011xxx */ ++ } ++ } ++ }else{ /* cbits == 8 */ ++ if(pi_read_bits(pi, 1) == 1) ++ n = pi_read_bits(pi, 1); ++ else{ ++ int bits = 0; ++ byte base = 2; ++ while(bits < 6){ ++ if(pi_read_bits(pi, 1) == 0) ++ break; ++ bits++; ++ base <<= 1; ++ } ++ n = pi_read_bits(pi, bits + 1) + base; ++ } ++ } ++ ++ return pi_table_get_value(pi, prev, (int) n); ++} ++ ++static int pi_read_position(pi) ++ struct pi_info *pi; ++{ ++ byte r; ++ if((r = pi_read_bits(pi, 2)) != 3) ++ return (int) r; ++ else ++ return (int) pi_read_bits(pi, 1) + 3; ++} ++ ++static data32 pi_read_length(pi) ++ struct pi_info *pi; ++{ ++ data32 r = 1; ++ int bits = 0; ++ while(pi_read_bits(pi, 1) == 1){ ++ r <<= 1; ++ bits++; ++ } ++ if(bits > 0) ++ return r + pi_read_bits(pi, bits); ++ return 1; ++} ++ ++static int pi_copy_pixels(pi, pic, cnt, pos, len) ++ struct pi_info *pi; ++ byte *pic; ++ int cnt, pos; ++ data32 len; ++{ ++ int s = 0, d = cnt; ++ int max = pi->width * pi->height; ++ switch(pos){ ++ case 0: ++ if(cnt < 2){ ++ if(pic[0] == pic[1]) ++ s = cnt - 2; ++ else ++ s = cnt - 4; ++ }else{ ++ if(pic[cnt - 2] == pic[cnt - 1]) ++ s = cnt - 2; ++ else ++ s = cnt - 4; ++ } ++ break; ++ case 1: ++ s = cnt - pi->width; ++ break; ++ case 2: ++ s = cnt - pi->width * 2; ++ break; ++ case 3: ++ s = cnt - pi->width + 1; ++ break; ++ case 4: ++ s = cnt - pi->width - 1; ++ } ++ ++ len *= 2; ++ while(s < 0 && len != 0 && d < max){ ++ pic[d++] = pic[-(s++) % 2]; ++ len--; ++ } ++ while(len != 0 && d < max){ ++ pic[d++] = pic[s++]; ++ len--; ++ } ++ return d; ++} ++ ++/* The main routine of `Pi' saver. */ ++int WritePi(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle, ++ comment) ++ FILE *fp; ++ byte *pic; ++ int ptype, w, h; ++ byte *rmap, *gmap, *bmap; ++ int numcols, colorstyle; ++ char *comment; ++{ ++ byte rtemp[256], gtemp[256], btemp[256]; ++ struct pi_info pi; ++ int e; ++ ++ if(DEBUG) fputs("WritePi\n", stderr); ++ pi_init_pi_info(&pi); ++ pi.fp = fp; ++ pi.width = w; ++ pi.height = h; ++ pi.writing_grey = (colorstyle == F_GREYSCALE); ++ if(ptype == PIC24){ ++ if(!(pic = Conv24to8(pic, w, h, 256, rtemp, gtemp, btemp))) ++ pi_memory_error("Conv24to8", "WritePi"); ++ rmap = rtemp; ++ gmap = gtemp; ++ bmap = btemp; ++ numcols = 256; ++ } ++ ++ if((e = setjmp(pi.jmp)) != 0){ ++ /* When an error occurs, comes here. */ ++ pi_cleanup_pi_info(&pi, 1); ++ if(DEBUG) fputs("\n", stderr); ++ return -1; ++ } ++ ++ pi.numcols = numcols; ++ pi_write_header(&pi, comment, rmap, gmap, bmap); ++ pi_compress(&pi, pic); ++ pi_write_gabage(&pi); ++ ++ pi_cleanup_pi_info(&pi, 1); ++ if(DEBUG) fputs("\n", stderr); ++ return 0; ++} ++ ++static void pi_write_header(pi, comm, r, g, b) ++ struct pi_info *pi; ++ char *comm; ++ byte *r, *g, *b; ++{ ++ byte buf[14]; ++ ++ if(DEBUG) pi_show_pi_info(pi); ++ ++ pi_write_id(pi); ++ pi_write_comment(pi, comm); ++ ++ buf[0] = buf[1] = buf[2] = 0; ++ buf[3] = pi->cbits = pi->numcols > 16 ? 8 : 4; ++ buf[4] = 'X'; ++ buf[5] = 'V'; ++ buf[6] = ' '; ++ buf[7] = ' '; ++ buf[8] = buf[9] = 0; ++ buf[10] = pi->width >> 8; ++ buf[11] = pi->width; ++ buf[12] = pi->height >> 8; ++ buf[13] = pi->height; ++ if(fwrite(buf, (size_t) 14, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_WRITE); ++ ++ pi_write_palette(pi, r, g, b); ++} ++ ++static void pi_write_id(pi) ++ struct pi_info *pi; ++{ ++ if(fwrite(pi_id, (size_t) 2, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_WRITE); ++} ++ ++static void pi_write_comment(pi, comm) ++ struct pi_info *pi; ++ char *comm; ++{ ++ if(comm){ ++ int i; ++ for(i = 0; comm[i]; i++){ ++ if(comm[i] == '\032') /* 0x1a, '^Z' */ ++ comm[i] = ' '; ++ } ++ if(i > 0){ ++ if(fwrite(comm, (size_t) i, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_WRITE); ++ } ++ } ++ ++ if(fwrite("\032\0", (size_t) 2, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_WRITE); ++} ++ ++static void pi_write_palette(pi, r, g, b) ++ struct pi_info *pi; ++ byte *r, *g, *b; ++{ ++ int i; ++ int pinum = 1 << pi->cbits; ++ char buf[3]; ++ ++ for(i = 0; i < pi->numcols; i++){ ++ buf[0] = *r++; ++ buf[1] = *g++; ++ buf[2] = *b++; ++ if(pi->writing_grey) ++ buf[0] = buf[1] = buf[2] = MONO(buf[0], buf[1], buf[2]); ++ if(fwrite(buf, (size_t) 3, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_WRITE); ++ } ++ for( ; i < pinum; i++){ ++ if(fwrite(buf, (size_t) 3, (size_t) 1, pi->fp) != 1) ++ pi_file_error(pi, PI_WRITE); ++ } ++ pi->numcols = pinum; ++} ++ ++/* The main routine to compress `Pi' format. */ ++static void pi_compress(pi, pic) ++ struct pi_info *pi; ++ byte *pic; ++{ ++ byte prev_col = 0; ++ int prev_pos = -1; ++ int cnt = 0, max_cnt = pi->width * pi->height; ++ pi_table_create(pi); ++ ++ if(pi->width > 2){ ++ int pos; ++ data32 len; ++ ++ pi_write_color(pi, 0, pic[0]); ++ pi_write_color(pi, pic[0], pic[1]); ++ pos = pi_test_matching(pi, pic, prev_pos, cnt, &len); ++ while(cnt < max_cnt){ ++ if(pos >= 0){ ++ pi_write_position(pi, pos); ++ pi_write_length(pi, len); ++ if((cnt += len * 2) >= max_cnt) ++ break; ++ prev_col = pic[cnt - 1]; ++ prev_pos = pos; ++ pos = pi_test_matching(pi, pic, prev_pos, cnt, &len); ++ }else{ ++ pi_write_position(pi, prev_pos); ++ prev_pos = -1; ++ while(pos < 0){ ++ pi_write_color(pi, (int) prev_col, pic[cnt]); ++ prev_col = pic[cnt]; ++ if(++cnt >= max_cnt) ++ break; ++ pi_write_color(pi, (int) prev_col, pic[cnt]); ++ prev_col = pic[cnt]; ++ if(++cnt >= max_cnt) ++ break; ++ pos = pi_test_matching(pi, pic, -1, cnt, &len); ++ if(pos < 0) ++ pi_write_bits(pi, 1, 1); ++ else ++ pi_write_bits(pi, 0, 1); ++ } ++ } ++ } ++ }else{ ++ while(cnt < max_cnt){ ++ pi_write_color(pi, (int) prev_col, pic[cnt]); ++ prev_col = pic[cnt++]; ++ } ++ } ++} ++ ++static void pi_write_gabage(pi) ++ struct pi_info *pi; ++{ ++ pi_write_bits(pi, 0, 32); ++} ++ ++static void pi_write_color(pi, prev, col) ++ struct pi_info *pi; ++ int prev, col; ++{ ++ int n = pi_table_lookup_value(pi, prev, col); ++ ++ if(pi->cbits == 4){ ++ if(n < 2) ++ pi_write_bits(pi, (data32) n | 2, 2); ++ else if(n < 4) ++ pi_write_bits(pi, (data32) n - 2, 3); ++ else if(n < 8) ++ pi_write_bits(pi, (data32) (n - 4) | 8, 5); ++ else ++ pi_write_bits(pi, (data32) (n - 8) | 24, 6); ++ }else{ /* cbits == 8 */ ++ if(n < 2){ ++ pi_write_bits(pi, (data32) n | 2, 2); ++ }else{ ++ int bits = 0; ++ byte base = 2; ++ while(bits < 6){ ++ if(n < (int) base * 2) ++ break; ++ bits++; ++ base <<= 1; ++ } ++ pi_write_bits(pi, 0, 1); ++ if(bits > 0) ++ pi_write_bits(pi, 0xffffffff, bits); ++ if(bits < 6) ++ pi_write_bits(pi, 0, 1); ++ pi_write_bits(pi, (data32) n - base, bits + 1); ++ } ++ } ++} ++ ++static int pi_test_matching(pi, pic, prev, cnt, len) ++ struct pi_info *pi; ++ byte *pic; ++ int prev, cnt; ++ data32 *len; ++{ ++ data32 lens[5]; ++ int pos, p; ++ int s, d = 0; ++ int max = pi->width * pi->height; ++ ++ for(pos = 0; pos < 5; pos++){ ++ switch(pos){ ++ case 0: ++ if(cnt < 2){ ++ if(pic[0] == pic[1]) ++ d = cnt - 2; ++ else ++ d = cnt - 4; ++ }else{ ++ if(pic[cnt - 2] == pic[cnt - 1]) ++ d = cnt - 2; ++ else ++ d = cnt - 4; ++ } ++ break; ++ case 1: ++ d = cnt - pi->width; ++ break; ++ case 2: ++ d = cnt - pi->width * 2; ++ break; ++ case 3: ++ d = cnt - pi->width + 1; ++ break; ++ case 4: ++ d = cnt - pi->width - 1; ++ } ++ s = cnt; ++ lens[pos] = 0; ++ ++ if(prev == 0 && pos == 0) ++ continue; ++ ++ while(d < max){ ++ if(pic[(d < 0) ? (-d) % 2 : d] != pic[s]) ++ break; ++ lens[pos]++; ++ d++; ++ s++; ++ } ++ ++ } ++ ++ for(pos = 0, p = 1; p < 5; p++){ ++ if(lens[p] >= lens[pos]) ++ pos = p; ++ } ++ ++ if(lens[pos] / 2 == 0) ++ return -1; ++ *len = lens[pos] / 2; ++ return pos; ++} ++ ++static void pi_write_position(pi, pos) ++ struct pi_info *pi; ++ int pos; ++{ ++ switch(pos){ ++ case 0: ++ pi_write_bits(pi, 0, 2); ++ break; ++ case 1: ++ pi_write_bits(pi, 1, 2); ++ break; ++ case 2: ++ pi_write_bits(pi, 2, 2); ++ break; ++ case 3: ++ pi_write_bits(pi, 6, 3); ++ break; ++ case 4: ++ pi_write_bits(pi, 7, 3); ++ break; ++ } ++} ++ ++static void pi_write_length(pi, len) ++ struct pi_info *pi; ++ data32 len; ++{ ++ int bits = 0; ++ data32 base = 1; ++ ++ while(len >= base * 2){ ++ bits++; ++ base <<= 1; ++ } ++ if(bits > 0){ ++ pi_write_bits(pi, 0xffffffff, bits); ++ pi_write_bits(pi, 0, 1); ++ pi_write_bits(pi, len - base, bits); ++ }else ++ pi_write_bits(pi, 0, 1); ++} ++ ++/* ++ * These pi_table_* functions manipulate the color table. ++ * pi_table_create: ++ * allocates and initializes a color table. ++ * pi_table_get_value: ++ * get the specified value, and move it to the top of the list. ++ * pi_table_lookup_value: ++ * look up the specified value, and move it to the top of the list. ++ */ ++static void pi_table_create(pi) ++ struct pi_info *pi; ++{ ++ struct ct_t *t; ++ int i; ++ byte mask = pi->numcols - 1; ++ pi->ct = pi_malloc(sizeof *pi->ct * pi->numcols, "pi_table_create(1)"); ++ for(i = 0, t = pi->ct; i < pi->numcols; i++, t++){ ++ int j; ++ byte v = i; ++ t->elt = pi_malloc(sizeof *t->elt * pi->numcols, "pi_table_create(2)"); ++ t->top = &t->elt[pi->numcols - 1]; ++ for(j = 0; j < pi->numcols; j++){ ++ v = (v + 1) & mask; ++ if(j > 0) ++ t->elt[j].old = &t->elt[j - 1]; ++ else ++ t->elt[0].old = t->top; ++ if(j < pi->numcols - 1) ++ t->elt[j].recent = &t->elt[j + 1]; ++ else ++ t->elt[j].recent = &t->elt[0]; ++ t->elt[j].val = v; ++ } ++ t->elt[0].old = t->top; ++ t->top->recent = &t->elt[0]; ++ } ++} ++ ++static byte pi_table_get_value(pi, left, num) ++ struct pi_info *pi; ++ int left, num; ++{ ++ struct ct_t *t = &pi->ct[left]; ++ struct elt_t *e = t->top; ++ if(left >= pi->numcols || num >= pi->numcols) ++ abort(); ++ if(num != 0){ ++ do { ++ e = e->old; ++ }while(--num != 0); ++ ++ e->old->recent = e->recent; ++ e->recent->old = e->old; ++ ++ e->recent = t->top->recent; ++ e->recent->old = e; ++ e->old = t->top; ++ t->top->recent = e; ++ ++ t->top = e; ++ } ++ return e->val; ++} ++ ++static int pi_table_lookup_value(pi, left, v) ++ struct pi_info *pi; ++ int left, v; ++{ ++ struct ct_t *t = &pi->ct[left]; ++ struct elt_t *e = t->top; ++ int num = 0; ++ ++ if(left >= pi->numcols || v >= pi->numcols) ++ abort(); ++ ++ while(e->val != v){ ++ e = e->old; ++ num++; ++ } ++ ++ if(num != 0){ ++ e->old->recent = e->recent; ++ e->recent->old = e->old; ++ ++ e->recent = t->top->recent; ++ e->recent->old = e; ++ e->old = t->top; ++ t->top->recent = e; ++ ++ t->top = e; ++ } ++ ++ return num; ++} ++ ++/* ++ * These 2 functions read or write to a bit stream. ++ * pi_read_bits: ++ * reads a specified-bit data from the bit stream. ++ * pi_write_bits: ++ * writes a specified-bit data to the bit stream. ++ */ ++static data32 pi_read_bits(pi, numbits) ++ struct pi_info *pi; ++ int numbits; ++{ ++ data32 r = 0; ++ ++ while(numbits > 0){ ++ while(pi->bs.rest > 0 && numbits > 0){ ++ r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0); ++ pi->bs.cur <<= 1; ++ pi->bs.rest--; ++ numbits--; ++ } ++ if(numbits > 0){ ++ int c; ++ if((c = fgetc(pi->fp)) == EOF) ++ pi_file_warning(pi, PI_CORRUPT); ++ pi->bs.cur = c; ++ pi->bs.rest = 8; ++ } ++ } ++ ++ return r; ++} ++ ++static void pi_write_bits(pi, dat, bits) ++ struct pi_info *pi; ++ data32 dat; ++ int bits; ++{ ++ data32 dat_mask = 1 << (bits - 1); ++ while(bits > 0){ ++ while(pi->bs.rest < 8 && bits > 0){ ++ pi->bs.cur <<= 1; ++ if(dat & dat_mask) ++ pi->bs.cur |= 1; ++ pi->bs.rest++; ++ bits--; ++ dat_mask >>= 1; ++ } ++ if(pi->bs.rest >= 8){ ++ if(fputc((int)pi->bs.cur, pi->fp) == EOF) ++ pi_file_error(pi, PI_WRITE); ++ pi->bs.cur = 0; ++ pi->bs.rest = 0; ++ } ++ } ++} ++ ++/* ++ * The routines to initialize or clean up. ++ * pi_inif_pi_info: ++ * initializes a pi_info structure. ++ * pi_cleanup_pi_info: ++ * cleanup pi_info structure. It frees allocated memories. ++ * pi_cleanup_pinfo: ++ * cleanup PICINFO structure when an error occurs. ++ */ ++static void pi_init_pi_info(pi) ++ struct pi_info *pi; ++{ ++ pi->fp = NULL; ++ pi->bs.rest = 0; ++ pi->bs.cur = 0; ++ pi->fsize = 0; ++ pi->mode = 0; ++ pi->width = pi->mode = 0; ++ pi->aspect = 1.0; ++ pi->cbits = 0; ++ pi->numcols = 0; ++ pi->cmap = NULL; ++ pi->ct = NULL; ++ pi->defcmap = 0; ++ pi->writing_grey = 0; ++} ++ ++static void pi_cleanup_pi_info(pi, writing) ++ struct pi_info *pi; ++ int writing; ++{ ++ if(pi->fp && !writing){ ++ fclose(pi->fp); ++ pi->fp = NULL; ++ } ++ if(pi->cmap){ ++ free(pi->cmap); ++ pi->cmap = NULL; ++ } ++ if(pi->ct){ ++ int i; ++ for(i = 0; i < pi->numcols; i++) ++ free(pi->ct[i].elt); ++ free(pi->ct); ++ pi->ct = NULL; ++ } ++} ++ ++static void pi_cleanup_pinfo(pinfo) ++ PICINFO *pinfo; ++{ ++ if(pinfo->pic){ ++ free(pinfo->pic); ++ pinfo->pic = NULL; ++ } ++ if(pinfo->comment){ ++ free(pinfo->comment); ++ pinfo->comment = NULL; ++ } ++} ++ ++/* ++ * Error handling routins. ++ * pi_memory_error: ++ * shows a error message, and terminates. ++ * pi_error: ++ * shows a non-file error message. ++ * pi_file_error: ++ * shows a file error message. ++ */ ++static void pi_memory_error(scm, fn) ++ char *scm, *fn; ++{ ++ char buf[128]; ++ sprintf(buf, "%s: couldn't allocate memory. (%s)", scm ,fn); ++ FatalError(buf); ++} ++ ++static void pi_error(pi, mn) ++ struct pi_info *pi; ++ int mn; ++{ ++ SetISTR(ISTR_WARNING, "%s", pi_msgs[mn]); ++ longjmp(pi->jmp, 1); ++} ++ ++static void pi_file_error(pi, mn) ++ struct pi_info *pi; ++ int mn; ++{ ++ if(feof(pi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", pi_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", pi_msgs[mn], ERRSTR(errno)); ++ longjmp(pi->jmp, 1); ++} ++ ++static void pi_file_warning(pi, mn) ++ struct pi_info *pi; ++ int mn; ++{ ++ if(feof(pi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", pi_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", pi_msgs[mn], ERRSTR(errno)); ++} ++ ++static void pi_show_pi_info(pi) ++ struct pi_info *pi; ++{ ++ fprintf(stderr, " file size: %ld.\n", pi->fsize); ++ fprintf(stderr, " mode: 0x%02x.\n", pi->mode); ++ fprintf(stderr, " image size: %dx%d.\n", pi->width, pi->height); ++ fprintf(stderr, " aspect: %f.\n", pi->aspect); ++ fprintf(stderr, " number of color bits: %d.\n", pi->cbits); ++ fprintf(stderr, " number of colors: %d.\n", pi->numcols); ++ fprintf(stderr, " using default colormap: %s.\n", ++ pi->defcmap ? "true" : "false"); ++ fprintf(stderr, " writing greyscale image: %s.\n", ++ pi->writing_grey ? "true" : "false"); ++} ++ ++/* ++ * Memory related routines. If failed, they calls pi_memory_error. ++ */ ++static void *pi_malloc(n, fn) ++ size_t n; ++ char *fn; ++{ ++ void *r = (void *) malloc(n); ++ if(r == NULL) ++ pi_memory_error("malloc", fn); ++ return r; ++} ++ ++static void *pi_realloc(p, n, fn) ++ void *p; ++ size_t n; ++ char *fn; ++{ ++ void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n); ++ if(r == NULL) ++ pi_memory_error("realloc", fn); ++ return r; ++} ++#endif /* HAVE_PI */ +diff -ruN xv-3.10a-bugfixes/xvpic.c xv-3.10a-enhancements/xvpic.c +--- xv-3.10a-bugfixes/xvpic.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvpic.c 2005-04-17 22:57:08.000000000 -0700 +@@ -0,0 +1,1285 @@ ++/* ++ * xvpic.c - load routine for `PIC' format pictures. ++ * ++ * The `PIC' format is used by many Japanese personal computer users. ++ */ ++ ++#include "xv.h" ++#include <setjmp.h> ++ ++#ifdef HAVE_PIC ++ ++typedef unsigned short data16; ++typedef unsigned int data32; ++ ++struct pic_info { ++ jmp_buf jmp; ++ FILE *fp; ++ struct { ++ int rest; ++ byte cur; ++ }bs; ++ long fsize; ++ int type, mode; ++ int width, height; ++ float aspect; ++ int cbits; ++ int cmapped; ++ byte *cmap; ++ int cached; ++ struct cache_t { ++ int newest; ++ struct cachenode_t { ++ data32 dat; ++ int newer, older; ++ } *node; ++ } cache; ++ int g_bits, r_bits, b_bits, i_bits; ++ int inv_gr; ++ int tiled256; ++ int numcols; ++ int writing_grey; ++ data32 *data; ++}; ++ ++static void pic_open_file PARM((struct pic_info*,char*)); ++static void pic_check_id PARM((struct pic_info*)); ++static void pic_read_comment PARM((struct pic_info*, char**)); ++static void pic_read_header PARM((struct pic_info*)); ++static void pic_expand_data PARM((struct pic_info*)); ++static int pic_expanding_read_len PARM((struct pic_info*)); ++static data32 pic_expanding_read_color PARM((struct pic_info*)); ++static void pic_expanding_read_chain ++ PARM((struct pic_info*, int, int, data32)); ++static void pic_make_xvpic ++ PARM((struct pic_info*, byte**, byte*, byte*, byte*)); ++ ++static void pic_write_id PARM((struct pic_info*)); ++static void pic_write_comment PARM((struct pic_info*, char*)); ++static void pic_write_header PARM((struct pic_info*)); ++static void pic_write_palette ++ PARM((struct pic_info*, byte*, byte*, byte*)); ++static void pic_make_sparse_data PARM((struct pic_info*, byte*)); ++static void pic_write_data PARM((struct pic_info*)); ++static void pic_write_length PARM((struct pic_info*, data32)); ++static void pic_write_color PARM((struct pic_info*, data32)); ++static void pic_write_chain ++ PARM((struct pic_info*, int, int, data32)); ++ ++static data32 pic_read_rgb PARM((struct pic_info*)); ++static data32 pic_read_color_code PARM((struct pic_info*)); ++static void pic_write_rgb PARM((struct pic_info*, data32)); ++static void pic_write_color_code PARM((struct pic_info*, data32)); ++ ++static void pic_cache_init PARM((struct pic_info*)); ++static data32 pic_cache_get_value PARM((struct pic_info*, int)); ++static void pic_cache_add_value PARM((struct pic_info*, data32)); ++static int pic_cache_lookup PARM((struct pic_info*, data32)); ++ ++static data32 pic_read_bits PARM((struct pic_info*, int)); ++static void pic_write_bits PARM((struct pic_info*, data32, int)); ++static byte pic_pad_bit PARM((int, data32)); ++ ++static void pic_init_info PARM((struct pic_info*)); ++static void pic_cleanup_pic_info PARM((struct pic_info*, int)); ++static void pic_cleanup_pinfo PARM((PICINFO*)); ++static void pic_memory_error PARM((char*, char*)); ++static void pic_error PARM((struct pic_info*, int)); ++static void pic_file_error PARM((struct pic_info*, int)); ++static void pic_file_warning PARM((struct pic_info*, int)); ++static void pic_show_pic_info PARM((struct pic_info*)); ++static void *pic_malloc PARM((size_t, char*)); ++static void *pic_realloc PARM((void*, size_t, char*)); ++ ++ ++static char *pic_id = "PIC"; ++ ++/* Error Messages */ ++static char *pic_msgs[] = { ++ NULL, ++#define PIC_OPEN 1 ++ "can't open file.", ++#define PIC_CORRUPT 2 ++ "file corrupted.", ++#define PIC_FORMAT 3 ++ "not PIC format.", ++#define PIC_SUPPORT 4 ++ "unsupported type.", ++#define PIC_COMMENT 5 ++ "can't read comment.", ++#define PIC_TYPE 6 ++ "bad machine type.", ++#define PIC_MODE 7 ++ "bad machine-dependent mode.", ++#define PIC_NUM_COLORS 8 ++ "bad number of colors.", ++#define PIC_SIZE 9 ++ "bad size.", ++#define PIC_ASPECT 10 ++ "bad aspect.", ++#define PIC_WRITE 11 ++ "write failed.", ++}; ++ ++#define H4(b) (((b) >> 4) & 0x0f) ++#define L4(b) ( (b) & 0x0f) ++ ++ ++/* The main routine to load a PIC file. */ ++int LoadPIC(fname, pinfo) ++ char *fname; ++ PICINFO *pinfo; ++{ ++ int e; ++ struct pic_info pic; ++ char buf[128]; ++ ++ if(DEBUG) fputs("LoadPIC:\n", stderr); ++ ++ pic_init_info(&pic); ++ ++ pinfo->comment = NULL; ++ if((e = setjmp(pic.jmp)) != 0){ ++ /* When an error occurs, comes here. */ ++ pic_cleanup_pic_info(&pic, 0); ++ pic_cleanup_pinfo(pinfo); ++ if(DEBUG) fputs("\n", stderr); ++ return 0; ++ } ++ ++ pic_open_file(&pic, fname); ++ pic_check_id(&pic); ++ pic_read_comment(&pic, &pinfo->comment); ++ pic_read_header(&pic); ++ pic_expand_data(&pic); ++ pic_make_xvpic(&pic, &pinfo->pic, pinfo->r, pinfo->g, pinfo->b); ++ ++ pinfo->w = pic.width; ++ if(pic.tiled256) ++ pinfo->h = pic.height * 2; ++ else ++ pinfo->h = pic.height; ++ pinfo->normw = pinfo->w; ++ pinfo->normh = pinfo->h; ++ pinfo->type = pic.cmapped ? PIC8 : PIC24; ++ pinfo->frmType = F_PIC; ++ pinfo->colType = F_FULLCOLOR; ++ strcpy(pinfo->fullInfo, "PIC"); ++ switch(pic.type){ ++ case 0x0: ++ strcat(pinfo->fullInfo, ", X68k"); ++ break; ++ case 0x1: ++ strcat(pinfo->fullInfo, ", PC-88VA"); ++ if(pic.mode & 1) ++ strcat(pinfo->fullInfo, ", HR"); ++ if(pic.mode & 2) ++ strcat(pinfo->fullInfo, ", tiled 256"); ++ break; ++ case 0x2: ++ strcat(pinfo->fullInfo, ", FM-TOWNS"); ++ if(pic.mode == 0x5){ ++ strcat(pinfo->fullInfo, ", low-resolution"); ++ }else{ ++ strcat(pinfo->fullInfo, ", high-resolution"); ++ } ++ break; ++ case 0x3: ++ strcat(pinfo->fullInfo, ", Macintosh"); ++ break; ++ case 0xf: ++ ; ++ } ++ sprintf(buf, " (%ld bytes)", pic.fsize); ++ strcat(pinfo->fullInfo, buf); ++ sprintf(pinfo->shrtInfo, "%dx%d(aspect %4.2f) PIC.", ++ pinfo->w, pinfo->h, pic.aspect); ++ if (!nopicadjust) ++ normaspect = pic.aspect; ++ ++ pic_cleanup_pic_info(&pic, 0); ++ if(DEBUG) fputs("\n", stderr); ++ return 1; ++} ++ ++static void pic_open_file(pi, fname) ++ struct pic_info *pi; ++ char *fname; ++{ ++ if((pi->fp = fopen(fname, "rb")) == NULL) ++ pic_file_error(pi, PIC_OPEN); ++ fseek(pi->fp, (size_t) 0, SEEK_END); ++ pi->fsize = ftell(pi->fp); ++ fseek(pi->fp, (size_t) 0, SEEK_SET); ++} ++ ++static void pic_check_id(pi) ++ struct pic_info *pi; ++{ ++ char buf[3]; ++ if(fread(buf, (size_t) 3, (size_t) 1, pi->fp) != 1) ++ pic_file_error(pi, PIC_CORRUPT); ++ if(strncmp(buf, pic_id, (size_t) 3) != 0) ++ pic_error(pi, PIC_FORMAT); ++} ++ ++static void pic_read_comment(pi, comm) ++ struct pic_info *pi; ++ char **comm; ++{ ++ /* The comment field is like: ++ * comment-string ^Z dummy \0 \0 ++ */ ++ int max = -1, i = 0; ++ int c; ++ ++ while(1){ ++ if((c = fgetc(pi->fp)) == EOF) ++ pic_file_error(pi, PIC_CORRUPT); ++ if(c == '\032') /* 0x1a, '^Z' */ ++ break; ++ if(max < i){ ++ max += 32; ++ *comm = pic_realloc(*comm, (size_t) max + 1, "pic_read_comment#1"); ++ } ++ (*comm)[i++] = c; ++ } ++ ++ if(max < i){ ++ max++; ++ *comm = pic_realloc(*comm, (size_t) max + 1, "pic_read_comment#2"); ++ } ++ (*comm)[i] = '\0'; ++ ++ while((c = fgetc(pi->fp)) != '\0'){ /* skip the dummy area */ ++ if(c == EOF) ++ pic_file_error(pi, PIC_CORRUPT); ++ } ++ ++ if(fgetc(pi->fp) != '\0') /* check the reserved byte */ ++ pic_error(pi, PIC_SUPPORT); ++} ++ ++static void pic_read_header(pi) ++ struct pic_info *pi; ++{ ++ pi->mode = pic_read_bits(pi, 4); ++ pi->type = pic_read_bits(pi, 4); ++ pi->cbits = pic_read_bits(pi, 16); ++ pi->width = pic_read_bits(pi, 16); ++ pi->height = pic_read_bits(pi, 16); ++ ++ /* machine-dependent setup. */ ++ switch(pi->type){ ++ case 0x0: /* X68K */ ++ if(pi->mode != 0) ++ pic_error(pi, PIC_MODE); ++ switch(pi->cbits){ ++ case 4: ++ pi->aspect = 1.0; ++ pi->g_bits = pi->r_bits = pi->b_bits = 5; ++ pi->i_bits = 1; ++ pi->cmapped = 1; ++ break; ++ ++ case 8: ++ pi->aspect = 4.0 / 3.0; ++ pi->g_bits = pi->r_bits = pi->b_bits = 5; ++ pi->i_bits = 1; ++ pi->cmapped = 1; ++ break; ++ ++ case 15: ++ pi->aspect = 4.0 / 3.0; ++ pi->g_bits = pi->r_bits = pi->b_bits = 5; ++ pi->cached = 1; ++ break; ++ ++ case 16: ++ pi->aspect = 4.0 / 3.0; ++ pi->g_bits = pi->r_bits = pi->b_bits = 5; ++ pi->i_bits = 1; ++ pi->cached = 1; ++ break; ++ ++ default: ++ pic_error(pi, PIC_NUM_COLORS); ++ } ++ break; ++ ++ case 0x1: /* PC-88VA */ ++ if(pi->height > 1000) ++ pic_error(pi, PIC_SIZE); ++ switch(pi->width * 1000 + pi->height){ ++ case 640400: ++ case 640204: ++ case 640200: ++ case 320408: ++ case 320400: ++ case 320200: ++ break; ++ default: ++ pic_error(pi, PIC_SIZE); ++ } ++ pi->aspect = 400.0 / pi->height; ++ pi->aspect *= pi->width / 640.0; ++ if(pi->mode & 0x1) /* HR mode */ ++ pi->aspect *= 2.0; ++ if(pi->mode & 0x2){ /* tiled 256 format */ ++ if(pi->cbits != 16) ++ pic_error(pi, PIC_NUM_COLORS); ++ pi->tiled256 = 1; ++ } ++ switch(pi->cbits){ ++ case 8: ++ pi->g_bits = pi->r_bits = 3; ++ pi->b_bits = 2; ++ break; ++ ++ case 12: ++ pi->g_bits = pi->r_bits = pi->b_bits = 4; ++ pi->cached = 1; ++ break; ++ ++ case 16: ++ pi->g_bits = 6; ++ pi->r_bits = pi->b_bits = 5; ++ pi->cached = 1; ++ break; ++ ++ default: ++ pic_error(pi, PIC_NUM_COLORS); ++ } ++ break; ++ ++ case 0x2: /* FM-TOWNS */ ++ if(pi->cbits != 15) ++ pic_error(pi, PIC_NUM_COLORS); ++ switch(pi->mode){ ++ case 0x5: ++ case 0xc: ++ break; ++ default: ++ pic_error(pi, PIC_MODE); ++ } ++ pi->g_bits = pi->r_bits = pi->b_bits = 5; ++ pi->cached = 1; ++ break; ++ ++ case 0x3: /* MAC */ ++ if(pi->cbits != 15) ++ pic_error(pi, PIC_NUM_COLORS); ++ pi->r_bits = pi->g_bits = pi->b_bits = 5; ++ pi->inv_gr = 1; ++ break; ++ ++ case 0xf: /* misc */ ++ { ++ byte ah, al; ++ ++ switch(pi->mode){ ++ case 0x0: ++ break; ++ case 0x1: ++ pi->aspect = 4.0 / 3.0; ++ break; ++ case 0xf: ++ break; ++ default: ++ pic_error(pi, PIC_MODE); ++ } ++ pic_read_bits(pi, 16); /* x */ ++ pic_read_bits(pi, 16); /* y */ ++ ah = pic_read_bits(pi, 8); ++ al = pic_read_bits(pi, 8); ++ if(ah > 0 && al > 0) ++ pi->aspect = (float) al / (int) ah; ++ else if(pi->mode == 0xf) ++ pic_error(pi, PIC_ASPECT); ++ switch(pi->cbits){ ++ case 4: ++ case 8: ++ pi->g_bits = pi->r_bits = pi->b_bits = pic_read_bits(pi, 8); ++ pi->cmapped = 1; ++ break; ++ ++ case 12: ++ pi->g_bits = pi->r_bits = pi->b_bits = 4; ++ pi->cached = 1; ++ break; ++ ++ case 15: ++ pi->g_bits = pi->r_bits = pi->b_bits = 5; ++ pi->cached = 1; ++ break; ++ ++ case 16: ++ pi->g_bits = pi->r_bits = pi->b_bits = 5; ++ pi->i_bits = 1; ++ pi->cached = 1; ++ break; ++ ++ case 24: ++ pi->g_bits = pi->r_bits = pi->b_bits = 8; ++ pi->cached = 1; ++ break; ++ ++ case 32: ++ pic_error(pi, PIC_SUPPORT); ++ break; ++ ++ default: ++ pic_error(pi, PIC_NUM_COLORS); ++ } ++ } ++ break; ++ ++ default: ++ pic_error(pi, PIC_TYPE); ++ } ++ ++ pi->numcols = 1 << pi->cbits; ++ ++ /* read palette data */ ++ if(pi->cmapped){ ++ int i; ++ pi->cmap = pic_malloc((size_t) 3 * pi->numcols, "pic_read_header#1"); ++ for(i = 0; i < pi->numcols; i++){ ++ data32 c = pic_read_rgb(pi); ++ pi->cmap[i * 3 ] = c >> 16 & 0xff; ++ pi->cmap[i * 3 + 1] = c >> 8 & 0xff; ++ pi->cmap[i * 3 + 2] = c & 0xff; ++ } ++ } ++ ++ /* setup color code cache */ ++ if(pi->cached) ++ pic_cache_init(pi); ++ ++ ++ pi->data = pic_malloc(sizeof(data32) * pi->width * pi->height, // GRR POSSIBLE OVERFLOW / FIXME ++ "pic_read_header#2"); ++ { ++ int i; ++ for(i = 0; i < pi->width * pi->height; i++) ++ pi->data[i] = 0xffffffff; ++ } ++ ++ if(DEBUG) ++ pic_show_pic_info(pi); ++} ++ ++/* The main routine to expand a PIC file. */ ++static void pic_expand_data(pi) ++ struct pic_info *pi; ++{ ++ int cnt; ++ data32 c; ++ pi->data[0] = c = 0; ++ for(cnt = -1; cnt < pi->width * pi->height; ){ ++ int len = pic_expanding_read_len(pi); ++ cnt += len; ++ if(cnt < pi->width * pi->height){ ++ int x = cnt % pi->width; ++ int y = cnt / pi->width; ++ data32 c = pic_expanding_read_color(pi); ++ pic_expanding_read_chain(pi, x, y, c); ++ } ++ } ++} ++ ++static int pic_expanding_read_len(pi) ++ struct pic_info *pi; ++{ ++ int len; ++ byte bits; ++ for(len = 2, bits = 1; pic_read_bits(pi, 1) == 1; bits++) ++ len <<= 1; ++ return len - 1 + pic_read_bits(pi, bits); ++} ++ ++static data32 pic_expanding_read_color(pi) ++ struct pic_info *pi; ++{ ++ if(pi->cached){ ++ byte b = pic_read_bits(pi, 1); ++ if(b){ ++ return pic_cache_get_value(pi, (int) pic_read_bits(pi, 7)); ++ }else{ ++ data32 c = pic_read_color_code(pi); ++ pic_cache_add_value(pi, c); ++ return c; ++ } ++ } ++ return pic_read_color_code(pi); ++} ++ ++static void pic_expanding_read_chain(pi, x, y, c) ++ struct pic_info *pi; ++ int x, y; ++ data32 c; ++{ ++ pi->data[y * pi->width + x] = c; ++ if(pic_read_bits(pi, 1) == 1){ ++ int fin = 0; ++ while(!fin){ ++ switch(pic_read_bits(pi, 2)){ ++ case 1: /* left */ ++ pi->data[(++y) * pi->width + (--x)] = c; ++ break; ++ case 2: /* middle */ ++ pi->data[(++y) * pi->width + x ] = c; ++ break; ++ case 3: /* right */ ++ pi->data[(++y) * pi->width + (++x)] = c; ++ break; ++ case 0: /* far or nothing */ ++ if(pic_read_bits(pi, 1) == 0) ++ fin = 1; ++ else{ ++ if(pic_read_bits(pi, 1) == 0) ++ pi->data[(++y) * pi->width + (x -= 2)] = c; ++ else ++ pi->data[(++y) * pi->width + (x += 2)] = c; ++ } ++ } ++ } ++ } ++} ++ ++/* ++ * Make a picture from the expanded data. ++ */ ++static void pic_make_xvpic(pi, xp, rp, gp, bp) ++ struct pic_info *pi; ++ byte **xp, *rp, *gp, *bp; ++{ ++ if(pi->cmapped){ ++ if(pi->tiled256) ++ *xp = pic_malloc((size_t) pi->width * pi->height * 2, // GRR POSSIBLE OVERFLOW / FIXME ++ "pic_make_xvpic#1"); ++ else ++ *xp = pic_malloc((size_t) pi->width * pi->height, // GRR POSSIBLE OVERFLOW / FIXME ++ "pic_make_xvpic#2"); ++ }else ++ *xp = pic_malloc((size_t) pi->width * pi->height * 3, // GRR POSSIBLE OVERFLOW / FIXME ++ "pic_make_xvpic#3"); ++ ++ if(pi->cmapped){ ++ int i; ++ ++ for(i = 0; i < pi->numcols; i++){ ++ rp[i] = pi->cmap[i * 3 ]; ++ gp[i] = pi->cmap[i * 3 + 1]; ++ bp[i] = pi->cmap[i * 3 + 2]; ++ } ++ ++ if(pi->tiled256){ ++ int pic_idx = 0, dat_idx; ++ data16 col = 0; ++ for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){ ++ if(pi->data[dat_idx] != 0xffffffff) ++ col = pi->data[dat_idx]; ++ (*xp)[pic_idx++] = col & 0xff; ++ (*xp)[pic_idx++] = col >> 8 & 0xff; ++ dat_idx++; ++ } ++ }else{ ++ int pic_idx = 0, dat_idx; ++ byte col = 0; ++ for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){ ++ if(pi->data[dat_idx] != 0xffffffff) ++ col = pi->data[dat_idx]; ++ (*xp)[pic_idx++] = col; ++ } ++ } ++ }else{ ++ int pic_idx = 0, dat_idx; ++ byte r = 0, g = 0, b = 0; ++ for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){ ++ if(pi->data[dat_idx] != 0xffffffff){ ++ data32 col = pi->data[dat_idx]; ++ r = col >> 16 & 0xff; ++ g = col >> 8 & 0xff; ++ b = col & 0xff; ++ } ++ (*xp)[pic_idx++] = r; ++ (*xp)[pic_idx++] = g; ++ (*xp)[pic_idx++] = b; ++ } ++ } ++} ++ ++ ++/* The main routine to write PIC file. */ ++int WritePIC(fp, pic0, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle, ++ comment) ++ FILE *fp; ++ byte *pic0; ++ int ptype, w, h; ++ byte *rmap, *gmap, *bmap; ++ int numcols, colorstyle; ++ char *comment; ++{ ++ struct pic_info pic; ++ int e; ++ ++ if(DEBUG) fputs("WritePIC:\n", stderr); ++ ++ pic_init_info(&pic); ++ pic.fp = fp; ++ pic.width = w; ++ pic.height = h; ++ pic.writing_grey = (colorstyle == F_GREYSCALE); ++ if(ptype != PIC24){ /* PIC8 */ ++ pic.cmapped = 1; ++ pic.cached = 0; ++ pic.cbits = 8; ++ pic.g_bits = ++ pic.r_bits = ++ pic.b_bits = 8; ++ pic.i_bits = 0; ++ pic.numcols = numcols; ++ }else{ /* PIC24 */ ++ pic.cmapped = 0; ++ pic.cached = 1; ++ pic.cbits = 24; ++ pic.g_bits = ++ pic.r_bits = ++ pic.b_bits = 8; ++ pic.i_bits = 0; ++ pic.numcols = 1 << 24; ++ pic_cache_init(&pic); ++ } ++ ++ if((e = setjmp(pic.jmp)) != 0){ ++ /* When an error occurs while writing, comes here. */ ++ pic_cleanup_pic_info(&pic, 1); ++ if(DEBUG) fputs("\n", stderr); ++ return -1; ++ } ++ ++ pic_write_id(&pic); ++ pic_write_comment(&pic, comment); ++ pic_write_header(&pic); ++ if(pic.cmapped) ++ pic_write_palette(&pic, rmap, gmap, bmap); ++ pic_make_sparse_data(&pic, pic0); ++ pic_write_data(&pic); ++ pic_write_bits(&pic, 0, 8); ++ ++ pic_cleanup_pic_info(&pic, 1); ++ if(DEBUG) fputs("\n", stderr); ++ return 0; ++} ++ ++static void pic_write_id(pi) ++ struct pic_info *pi; ++{ ++ if(fwrite("PIC", (size_t) 3, (size_t) 1, pi->fp) != 1) ++ pic_file_error(pi, PIC_WRITE); ++} ++ ++static void pic_write_comment(pi, comm) ++ struct pic_info *pi; ++ char *comm; ++{ ++ if(comm){ ++ while(*comm){ ++ int c = *comm; ++ if(c == '\032') ++ c = ' '; ++ if(fputc(*comm, pi->fp) == EOF) ++ pic_file_error(pi, PIC_WRITE); ++ comm++; ++ } ++ } ++ /* write ^Z, 0, and reserved. */ ++ if(fwrite("\032\0\0", (size_t)3, (size_t) 1, pi->fp) != 1) ++ pic_file_error(pi, PIC_WRITE); ++} ++ ++static void pic_write_header(pi) ++ struct pic_info *pi; ++{ ++ if(DEBUG) pic_show_pic_info(pi); ++ pic_write_bits(pi, (data32) 0, 4); /* mode: 1:1 */ ++ pic_write_bits(pi, (data32) 0xf, 4); /* type: misc */ ++ pic_write_bits(pi, (data32) pi->cbits, 16); /* bits */ ++ pic_write_bits(pi, (data32) pi->width, 16); /* width */ ++ pic_write_bits(pi, (data32) pi->height, 16); /* height */ ++ pic_write_bits(pi, (data32) 0xffff, 16); /* x: unused */ ++ pic_write_bits(pi, (data32) 0xffff, 16); /* y: unused */ ++ pic_write_bits(pi, (data32) 0x0101, 16); /* real aspect */ ++} ++ ++static void pic_write_palette(pi, r, g, b) ++ struct pic_info *pi; ++ byte *r, *g, *b; ++{ ++ int i; ++ data32 rgb = 0; ++ pic_write_bits(pi, (data32) pi->g_bits, 8); ++ for(i = 0; i < pi->numcols; i++){ ++ rgb = (data32) *r++ << 16 | (data32) *g++ << 8 | (data32) *b++; ++ pic_write_rgb(pi, rgb); ++ } ++ for( ; i < 256; i++) ++ pic_write_rgb(pi, rgb); ++} ++ ++static void pic_make_sparse_data(pi, dat) ++ struct pic_info *pi; ++ byte *dat; ++{ ++ int i; ++ data32 c; ++ ++ pi->data = pic_malloc(sizeof(data32) * pi->width * pi->height, // GRR POSSIBLE OVERFLOW / FIXME ++ "pic_make_sparse_data"); ++ ++ if(pi->cmapped){ ++ c = 0; ++ for(i = 0; i < pi->width * pi->height; i++){ ++ if(c != dat[i]) ++ c = pi->data[i] = dat[i]; ++ else ++ pi->data[i] = 0xffffffff; ++ } ++ }else{ ++ int j = 0; ++ c = 0; ++ for(i = 0; i < pi->width * pi->height; i++){ ++ data32 r, g, b, t; ++ r = dat[j++]; ++ g = dat[j++]; ++ b = dat[j++]; ++ t = r << 16 | g << 8 | b; ++ if(c != t) ++ c = pi->data[i] = t; ++ else ++ pi->data[i] = 0xffffffff; ++ } ++ } ++} ++ ++static void pic_write_data(pi) ++ struct pic_info *pi; ++{ ++ int i; ++ int max = pi->width * pi->height; ++ data32 c = 0; ++ ++ i = -1; ++ while(i < max){ ++ int j; ++ for(j = i + 1; j < max; j++){ ++ if(pi->data[j] != 0xffffffff) ++ break; ++ } ++ pic_write_length(pi, (data32) j - i); ++ i = j; ++ if(i < max){ ++ pic_write_color(pi, c = pi->data[i]); ++ pic_write_chain(pi, i % pi->width, i / pi->width, c); ++ } ++ } ++} ++ ++static void pic_write_length(pi, len) ++ struct pic_info *pi; ++ data32 len; ++{ ++ int bits = 0; /* leading 1's */ ++ int max = 2; ++ ++ while(len > max){ ++ max = (max + 1) * 2; ++ bits++; ++ } ++ pic_write_bits(pi, 0xffffffff, bits); ++ pic_write_bits(pi, 0, 1); ++ pic_write_bits(pi, len - max / 2, bits + 1); ++} ++ ++static void pic_write_color(pi, c) ++ struct pic_info *pi; ++ data32 c; ++{ ++ if(pi->cached){ ++ int idx = pic_cache_lookup(pi, c); ++ if(idx < 0){ /* not found */ ++ pic_write_bits(pi, 0, 1); ++ pic_write_color_code(pi, c); ++ pic_cache_add_value(pi, c); ++ }else{ /* found */ ++ pic_write_bits(pi, (data32) 0xffffffff, 1); ++ pic_write_bits(pi, (data32) idx, 7); ++ } ++ }else ++ pic_write_color_code(pi, c); ++} ++ ++static void pic_write_chain(pi, x, y, c) ++ struct pic_info *pi; ++ int x, y; ++ data32 c; ++{ ++ int ctr = (y + 1) * pi->width + x; ++ ++ if(y < pi->height - 1 && ++ ( pi->data[ctr ] == c || ++ (x > 0 && pi->data[ctr - 1] == c) || ++ (x < pi->width - 1 && pi->data[ctr + 1] == c) || ++ (x > 1 && pi->data[ctr - 2] == c) || ++ (x < pi->width - 2 && pi->data[ctr + 2] == c))){ ++ pic_write_bits(pi, 1, 1); ++ while(++y < pi->height){ ++ if(pi->data[ctr] == c){ /* center */ ++ pic_write_bits(pi, 2, 2); ++ pi->data[ctr] = 0xffffffff; ++ ctr += pi->width; ++ }else if(x > 0 && pi->data[ctr - 1] == c){ /* left */ ++ pic_write_bits(pi, 1, 2); ++ pi->data[ctr - 1] = 0xffffffff; ++ ctr += pi->width - 1; ++ }else if(x < pi->width - 1 && pi->data[ctr + 1] == c){/* right */ ++ pic_write_bits(pi, 3, 2); ++ pi->data[ctr + 1] = 0xffffffff; ++ ctr += pi->width + 1; ++ }else if(x > 1 && pi->data[ctr - 2] == c){ /* 2-left */ ++ pic_write_bits(pi, 2, 4); ++ pi->data[ctr - 2] = 0xffffffff; ++ ctr += pi->width - 2; ++ }else if(x < pi->width - 2 && pi->data[ctr + 2] == c){/* 2-right */ ++ pic_write_bits(pi, 3, 4); ++ pi->data[ctr + 2] = 0xffffffff; ++ ctr += pi->width + 2; ++ }else /* nothing */ ++ break; ++ } ++ pic_write_bits(pi, 0, 3); ++ }else ++ pic_write_bits(pi, 0, 1); ++} ++ ++ ++/* ++ * These 4 functions read or write a color. ++ * ++ * pic_read_rgb: ++ * reads an RGB. Each bit length is [rgb]_bits, but ++ * it is expanded to 8bits when returned. ++ * ++ * pic_read_color_code: ++ * reads a color code, whose length is cbits. ++ * It is the index to the colormap or RGB itself. ++ * ++ * pic_write_rgb: ++ * writes an RGB value. ++ * ++ * pic_write_color_code: ++ * writes a color code. ++ */ ++static data32 pic_read_rgb(pi) ++ struct pic_info *pi; ++{ ++ int rb = pi->r_bits, gb = pi->g_bits, bb = pi->b_bits; ++ byte r, g, b; ++ if(pi->inv_gr){ ++ r = pic_read_bits(pi, rb); ++ g = pic_read_bits(pi, gb); ++ }else{ ++ g = pic_read_bits(pi, gb); ++ r = pic_read_bits(pi, rb); ++ } ++ b = pic_read_bits(pi, bb); ++ if(pi->i_bits){ ++ byte i; ++ i = pic_read_bits(pi, pi->i_bits); ++ r = r << pi->i_bits | i; ++ g = g << pi->i_bits | i; ++ b = b << pi->i_bits | i; ++ rb += pi->i_bits; ++ gb += pi->i_bits; ++ bb += pi->i_bits; ++ } ++ r = pic_pad_bit(rb, r); ++ g = pic_pad_bit(gb, g); ++ b = pic_pad_bit(bb, b); ++ ++ return (data32) r << 16 | (data32) g << 8 | (data32) b; ++} ++ ++static data32 pic_read_color_code(pi) ++ struct pic_info *pi; ++{ ++ if(pi->cmapped) ++ return pic_read_bits(pi, pi->cbits); ++ return pic_read_rgb(pi); ++} ++ ++static void pic_write_rgb(pi, rgb) ++ struct pic_info *pi; ++ data32 rgb; ++{ ++ byte r = rgb >> 16; ++ byte g = rgb >> 8; ++ byte b = rgb; ++ if(pi->writing_grey) ++ r = g = b = MONO(r, g, b); ++ pic_write_bits(pi, g, pi->g_bits); ++ pic_write_bits(pi, r, pi->r_bits); ++ pic_write_bits(pi, b, pi->b_bits); ++} ++ ++static void pic_write_color_code(pi, code) ++ struct pic_info *pi; ++ data32 code; ++{ ++ if(pi->cmapped){ ++ pic_write_bits(pi, code, pi->cbits); ++ }else{ ++ pic_write_rgb(pi, code); ++ } ++} ++ ++ ++/* ++ * These pic_cache_* functions are an implementation of the color cache. ++ * ++ * pic_cache_init: ++ * initializes the cache. ++ * ++ * pic_cache_get_value: ++ * gets a color indexed by the argument `idx'. ++ * It updates the `most recently used' time. ++ * ++ * pic_cache_add_value: ++ * adds a color to the top of the cache list. ++ */ ++static void pic_cache_init(pi) ++ struct pic_info *pi; ++{ ++ int i; ++ pi->cache.node = pic_malloc(sizeof(struct cachenode_t) * 128, ++ "pic_cache_init"); ++ for(i = 0; i < 128; i++){ ++ pi->cache.node[i].newer = i + 1; ++ pi->cache.node[i].older = i - 1; ++ pi->cache.node[i].dat = 0; ++ } ++ pi->cache.node[ 0].older = 127; ++ pi->cache.node[127].newer = 0; ++ pi->cache.newest = 0; ++} ++ ++static data32 pic_cache_get_value(pi, idx) ++ struct pic_info *pi; ++ int idx; ++{ ++ struct cachenode_t *p = pi->cache.node; ++ int n = pi->cache.newest; ++ if(n != idx){ ++ p[p[idx].newer].older = p[idx].older; ++ p[p[idx].older].newer = p[idx].newer; ++ ++ p[p[n].newer].older = idx; ++ p[idx].newer = p[n].newer; ++ p[n].newer = idx; ++ p[idx].older = n; ++ ++ pi->cache.newest = idx; ++ } ++ return pi->cache.node[idx].dat; ++} ++ ++static void pic_cache_add_value(pi, dat) ++ struct pic_info *pi; ++ data32 dat; ++{ ++ pi->cache.newest = pi->cache.node[pi->cache.newest].newer; ++ pi->cache.node[pi->cache.newest].dat = dat; ++} ++ ++static int pic_cache_lookup(pi, dat) ++ struct pic_info *pi; ++ data32 dat; ++{ ++ int i; ++ for(i = 0; i < 128; i++){ ++ if(pi->cache.node[i].dat == dat){ ++ pic_cache_get_value(pi, i); ++ return i; ++ } ++ } ++ return -1; ++} ++ ++ ++/* ++ * These pic_{read,write}_bits functions access the bit stream. ++ * pic_read_bits: ++ * reads the specified bits from the file. ++ * ++ * pic_write_bits: ++ * writes the specified bits to the file. ++ */ ++static data32 pic_read_bits(pi, bits) ++ struct pic_info *pi; ++ int bits; ++{ ++ data32 r = 0; ++ ++ while(bits > 0){ ++ while(pi->bs.rest > 0 && bits > 0){ ++ r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0); ++ pi->bs.cur <<= 1; ++ pi->bs.rest--; ++ bits--; ++ } ++ if(bits > 0){ ++ int c; ++ if((c = fgetc(pi->fp)) == EOF){ ++ pic_file_warning(pi, PIC_CORRUPT); ++ c = 0; ++ } ++ pi->bs.cur = c; ++ pi->bs.rest = 8; ++ } ++ } ++ ++ return r; ++} ++ ++static void pic_write_bits(pi, dat, bits) ++ struct pic_info *pi; ++ data32 dat; ++ int bits; ++{ ++ data32 dat_mask = 1 << (bits - 1); ++ while(bits > 0){ ++ while(pi->bs.rest < 8 && bits > 0){ ++ pi->bs.cur <<= 1; ++ if(dat & dat_mask) ++ pi->bs.cur |= 1; ++ pi->bs.rest++; ++ bits--; ++ dat_mask >>= 1; ++ } ++ if(pi->bs.rest >= 8){ ++ if(fputc((int)pi->bs.cur, pi->fp) == EOF) ++ pic_error(pi, PIC_WRITE); ++ pi->bs.cur = 0; ++ pi->bs.rest = 0; ++ } ++ } ++} ++ ++ ++/* ++ * This function extends sub-8-bit data to 8-bit data using bit-replication. ++ */ ++static byte pic_pad_bit(bits, dat) ++ int bits; ++ data32 dat; ++{ ++ switch(bits){ ++ case 1: ++ if(dat & 1) ++ dat = 0xff; ++ else ++ dat = 0; ++ break; ++ case 2: ++ dat = dat << 6 | dat << 4 | dat << 2 | dat; ++ break; ++ case 3: ++ dat = dat << 5 | dat << 2 | dat >> 1; ++ break; ++ case 4: ++ dat = dat << 4 | dat; ++ break; ++ case 5: ++ dat = dat << 3 | dat >> 2; ++ break; ++ case 6: ++ dat = dat << 2 | dat >> 4; ++ break; ++ case 7: ++ dat = dat << 1 | dat >> 6; ++ } ++ ++ return dat; ++} ++ ++/* ++ * These functions initialize or clean up structures. ++ * pic_init_info: ++ * initializes a pic_info structure. ++ * pic_cleanup_pic_info: ++ * cleans up a pic_info structure. ++ * pic_cleanup_pinfo: ++ * cleans up a PICINFO structure. ++ */ ++static void pic_init_info(pi) ++ struct pic_info *pi; ++{ ++ pi->fp = NULL; ++ pi->bs.rest = 0; ++ pi->bs.cur = '\0'; ++ pi->type = pi->mode = 0; ++ pi->width = pi->height = 0; ++ pi->aspect = 1.0; ++ pi->cbits = 0; ++ pi->cmapped = pi->cached = 0; ++ pi->cache.node = NULL; ++ pi->cmap = NULL; ++ pi->g_bits = pi->r_bits = pi->b_bits = pi->i_bits = 0; ++ pi->inv_gr = 0; ++ pi->tiled256 = 0; ++ pi->numcols = 0; ++ pi->writing_grey = 0; ++} ++ ++static void pic_cleanup_pic_info(pi, writing) ++ struct pic_info *pi; ++ int writing; ++{ ++ if(!writing && pi->fp) ++ fclose(pi->fp); ++ if(pi->cmap) ++ free(pi->cmap); ++ if(pi->cache.node) ++ free(pi->cache.node); ++ if(pi->data) ++ free(pi->data); ++ pi->fp = NULL; ++ pi->cmap = NULL; ++ pi->cache.node = NULL; ++ pi->data = NULL; ++} ++ ++static void pic_cleanup_pinfo(pinfo) ++ PICINFO *pinfo; ++{ ++ if(pinfo->pic){ ++ free(pinfo->pic); ++ pinfo->pic = NULL; ++ } ++ if(pinfo->comment){ ++ free(pinfo->comment); ++ pinfo->comment = NULL; ++ } ++} ++ ++/* ++ * Error Handlers. ++ * pic_memory_error: ++ * shows an error message and terminates. ++ * pic_error: ++ * shows a non-file error message and jumps to the entry for errors. ++ * pic_file_error: ++ * shows a file error message and jumps to the entry for errors. ++ * pic_file_warning: ++ * shows a file warning message. ++ */ ++static void pic_memory_error(scm, fn) ++ char *scm, *fn; ++{ ++ char buf[128]; ++ sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn); ++ FatalError(buf); ++} ++ ++static void pic_error(pi, mn) ++ struct pic_info *pi; ++ int mn; ++{ ++ SetISTR(ISTR_WARNING, "%s", pic_msgs[mn]); ++ longjmp(pi->jmp, 1); ++} ++ ++static void pic_file_error(pi, mn) ++ struct pic_info *pi; ++ int mn; ++{ ++ if(feof(pi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", pic_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", pic_msgs[mn], ERRSTR(errno)); ++ longjmp(pi->jmp, 1); ++} ++ ++static void pic_file_warning(pi, mn) ++ struct pic_info *pi; ++ int mn; ++{ ++ if(feof(pi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", pic_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", pic_msgs[mn], ERRSTR(errno)); ++} ++ ++static void pic_show_pic_info(pi) ++ struct pic_info *pi; ++{ ++ fprintf(stderr, " file size: %ld.\n", pi->fsize); ++ ++ fputs(" machine: ", stderr); ++ switch(pi->type){ ++ case 0x0: ++ fputs("X68k", stderr); ++ break; ++ case 0x1: ++ fputs("PC-88VA", stderr); ++ if(pi->mode & 1) ++ fputs(",HR", stderr); ++ if(pi->mode & 2) ++ fputs(",tiled256", stderr); ++ break; ++ case 0x2: ++ fprintf(stderr, ++ "FM-TOWNS,%s-resolution", pi->mode == 5 ? "low" : "high"); ++ break; ++ case 0x3: ++ fputs("Macintosh", stderr); ++ break; ++ case 0xf: ++ fputs("misc", stderr); ++ } ++ fputs("\n", stderr); ++ ++ fprintf(stderr, " image size: %dx%d\n", pi->width, pi->height); ++ fprintf(stderr, " aspect: %f\n", pi->aspect); ++ fprintf(stderr, " cache: %s\n", pi->cached ? "on" : "off"); ++ fprintf(stderr, " colormap: %s\n", pi->cmapped ? "on" : "off"); ++ fprintf(stderr, " number of color bits: %d\n", pi->cbits); ++ fprintf(stderr, " number of RGB bits: R%d,G%d,B%d,I%d\n", ++ pi->r_bits, pi->g_bits, pi->b_bits, pi->i_bits); ++ fprintf(stderr, " inverted G&R: %s\n", pi->inv_gr ? "true" : "false"); ++ fprintf(stderr, " number of colors: %d\n", pi->numcols); ++} ++ ++/* Memory related routines. */ ++static void *pic_malloc(n, fn) ++ size_t n; ++ char *fn; ++{ ++ void *r = (void *) malloc(n); ++ if(r == NULL) ++ pic_memory_error("malloc", fn); ++ return r; ++} ++ ++static void *pic_realloc(p, n, fn) ++ void *p; ++ size_t n; ++ char *fn; ++{ ++ void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n); ++ if(r == NULL) ++ pic_memory_error("realloc", fn); ++ return r; ++} ++#endif /* HAVE_PIC */ +diff -ruN xv-3.10a-bugfixes/xvpic2.c xv-3.10a-enhancements/xvpic2.c +--- xv-3.10a-bugfixes/xvpic2.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvpic2.c 2005-04-17 22:56:07.000000000 -0700 +@@ -0,0 +1,3608 @@ ++/* ++ * $Id: xvpic2.c,v 2.9.1.14 1995/04/24 15:34:15 ikeyan Exp $ ++ * xvpic2.c - load and save routines for `PIC2' format pictures. ++ * ++ * ++ * Outline ++ * ======= ++ * xvpic2.c supports the PIC2 format image file. It is used some ++ * Japanese personal computer users. ++ * ++ * The PIC2 format is designed by A.Yanagisawa. It is an excellent ++ * format except for its encode/decode speed. ;-) ++ * ++ * The features of the PIC2 format: ++ * - Powerful header information (included author, filename, title, ++ * saver, product number, created date and comment). ++ * - Reversible compression, and very high compression ratio (in many ++ * cases, a higher compression ratio than the JPEG compression; ++ * because of its compression method, PIC2 is especially good at ++ * pictures like cell animation). ++ * - Can handle full-color (24 bits) image. ++ * - Can include multi image blocks into one PIC2 file. ++ * - Have four different block format (P2SS, P2SF, P2BM and ++ * P2BI). P2SS format uses arithmetic compression for storing ++ * data. P2SF uses normal run-length compression. P2BM and P2BI is ++ * raw image format. Select any one according to the situation. ++ * ++ * Explanation of the PIC2 compression: ++ ++ * - In the first place, try to record pixel color, uses color caches ++ * which keep some recent colors, and formed according to color's ++ * frequency. PIC2 has some color cache spaces that are switched by ++ * upper pixel value of current pixel. If cache is hit, record ++ * that. ++ * - Unfortunately, in the case of color cache didn't hit, record the ++ * difference from the value estimated with the value of upper and ++ * left pixel of current pixel (similar to PNG's AVG predictor). ++ * - And extract image's color chain if exist, and record that (it ++ * results in image's outline). ++ * - In all cases, arithmetic compression is used in the final stage ++ * before writing the file, which in theory produces the ideal ++ * compression ratio (P2SS). ++ * ++ * Features ++ * ======== ++ * - Support 3,6,9,12,15,18,21,24bit PIC2 format (Load/Save). ++ * - Support all image block formats of PIC2 (Load/Save). ++ * - Support multi block PIC2 file (Load/Save). ++ * ++ * ++ * Bugs ++ * ==== ++ * - Unsupport 8bit PIC2 image file. ++ * ++ * If you find other bugs (surely exist :-)), send me bug-report. ++ * ++ * ++ * Author ++ * ====== ++ * IKEMOTO Masahiro <ikeyan@airlab.cs.ritsumei.ac.jp> ++ */ ++ ++#define PIC2_IGNORE_UNUSED_FUNCTIONS ++#define NEEDSDIR ++ ++#include "xv.h" ++#include <setjmp.h> ++ ++#ifdef HAVE_PIC2 ++ ++typedef unsigned long pixel; ++ ++#define pic2_cextoshort(addr) ( \ ++ (((short) (((byte *) addr)[0])) << 8) | \ ++ ( (short) (((byte *) addr)[1])) \ ++) ++#define pic2_cextolong(addr) ( \ ++ (((long) (((byte *) addr)[0])) << 24) | \ ++ (((long) (((byte *) addr)[1])) << 16) | \ ++ (((long) (((byte *) addr)[2])) << 8) | \ ++ ( (long) (((byte *) addr)[3])) \ ++) ++#define pic2_shorttocex(addr, n) { \ ++ ((byte *) addr)[0] = (((unsigned short) (n) >> 8) & 0xff); \ ++ ((byte *) addr)[1] = ( (unsigned short) (n) & 0xff); \ ++} ++#define pic2_longtocex(addr, n) { \ ++ ((byte *) addr)[0] = (((unsigned long) (n) >> 24) & 0xff); \ ++ ((byte *) addr)[1] = (((unsigned long) (n) >> 16) & 0xff); \ ++ ((byte *) addr)[2] = (((unsigned long) (n) >> 8) & 0xff); \ ++ ((byte *) addr)[3] = ( (unsigned long) (n) & 0xff); \ ++} ++#define pic2_shift_bits(b, n) (((n) > 0) ? ((b) << (n)) : ((b) >> -(n))) ++ ++#define PIC2_READ_MODE 0 ++#define PIC2_WRITE_MODE 1 ++ ++#define PIC2_ARITH_CACHE 32 ++#define PIC2_ARITH_CONTEXT 128 ++#define PIC2_FAST_CACHE 64 ++ ++#define PIC2_HEADER_SIZE 124 ++#define PIC2_BLOCK_HEADER_SIZE 26 ++ ++struct pic2_header { ++ char magic[4]; ++ char name[18]; ++ char subtitle[8]; ++ char crlf0[2]; ++ char title[30]; ++ char crlf1[2]; ++ char saver[30]; ++ char crlf2[2]; ++ char eof[1]; ++ char reserve0[1]; ++ short flag; ++ short no; ++ long time; ++ long size; ++ short depth; ++ short x_aspect; ++ short y_aspect; ++ short x_max; ++ short y_max; ++ long reserve1; ++}; ++ ++struct pic2_block { ++ char id[4]; ++ long size; ++ short flag; ++ short x_wid; ++ short y_wid; ++ short x_offset; ++ short y_offset; ++ long opaque; ++ long reserve; ++}; ++ ++struct pic2_info { ++ jmp_buf jmp; ++ FILE *fp; ++ struct { ++ int rest; ++ byte cur; ++ int bits; ++ char zero; ++ }bs; ++ long fsize; ++ struct pic2_header *header; ++ struct pic2_block *block; ++ int n_pal; ++ int pal_bits; ++ byte pal[256][3]; ++ char *comment; ++ char mode; ++ long next_pos; ++ long block_pos; ++ short x_max; ++ short y_max; ++ int ynow; ++ byte *buf; ++ pixel *vram_prev; ++ pixel *vram_now; ++ pixel *vram_next; ++ short *flag_now; ++ short *flag_next; ++ short *flag2_now; ++ short *flag2_next; ++ short *flag2_next2; ++ pixel (*cache)[PIC2_ARITH_CACHE]; ++ unsigned short *cache_pos; ++ unsigned short *mulu_tab; ++ long aa; ++ long cc; ++ long dd; ++ char cache_hit_c; ++ int (*next_line) PARM((struct pic2_info *, pixel **)); ++ char writing_grey; ++ char pagebname[64]; ++ int pnum; ++}; ++ ++static void pic2_open_file PARM((struct pic2_info*,char*)); ++static void pic2_read_header PARM((struct pic2_info*)); ++static void pic2_read_block_header1 PARM((struct pic2_info*)); ++static void pic2_read_block_header2 PARM((struct pic2_info*)); ++static short pic2_arith_decode_bit PARM((struct pic2_info*,int)); ++static short pic2_arith_decode_nn PARM((struct pic2_info*,int)); ++static void pic2_arith_expand_chain PARM((struct pic2_info*,int,int,pixel)); ++static short pic2_arith_get_number PARM((struct pic2_info*,int,int)); ++static pixel pic2_arith_read_color PARM((struct pic2_info*,int)); ++static int pic2_arith_expand_line PARM((struct pic2_info*,pixel**)); ++static int pic2_arith_loader_init PARM((struct pic2_info*)); ++static int pic2_fast_read_length PARM((struct pic2_info*)); ++static void pic2_fast_expand_chain PARM((struct pic2_info*,int,pixel)); ++static pixel pic2_fast_read_color PARM((struct pic2_info*,pixel)); ++static int pic2_fast_expand_line PARM((struct pic2_info*,pixel**)); ++static int pic2_fast_loader_init PARM((struct pic2_info*)); ++static int pic2_beta_expand_line PARM((struct pic2_info*,pixel**)); ++static int pic2_beta_loader_init PARM((struct pic2_info*)); ++static void pic2_make_xvpic PARM((struct pic2_info*,byte**, ++ byte*,byte*,byte*)); ++static void pic2_make_pagefile PARM((struct pic2_info*,char*,int)); ++static void pic2_setup_pic2_info PARM((struct pic2_info*, ++ char*,char*,char*,char*, ++ int,int,int,int,int,int,char *)); ++static void pic2_append PARM((struct pic2_info*)); ++static void pic2_write_header1 PARM((struct pic2_info*)); ++static void pic2_write_header2 PARM((struct pic2_info*)); ++static void pic2_write_block_header PARM((struct pic2_info*)); ++static void pic2_arith_write_zero_bit PARM((struct pic2_info*)); ++static void pic2_arith_flush_bit_buf PARM((struct pic2_info*)); ++static void pic2_arith_carry_bit PARM((struct pic2_info*)); ++static void pic2_arith_encode_bit PARM((struct pic2_info*,int,int)); ++static void pic2_arith_encode_nbyte PARM((struct pic2_info*,int,int,int)); ++static void pic2_arith_encode_nn PARM((struct pic2_info*,int,int)); ++static void pic2_arith_press_chain PARM((struct pic2_info*,int)); ++static void pic2_arith_put_number PARM((struct pic2_info*,int,int,int)); ++static void pic2_arith_write_color PARM((struct pic2_info*,int)); ++static void pic2_arith_press_line2 PARM((struct pic2_info*)); ++static int pic2_arith_press_line PARM((struct pic2_info*,pixel**)); ++static int pic2_arith_saver_init PARM((struct pic2_info*,pixel**)); ++static void pic2_fast_write_length PARM((struct pic2_info*,int)); ++static void pic2_fast_press_chain PARM((struct pic2_info*,int)); ++static void pic2_fast_press_chain2 PARM((struct pic2_info*,int)); ++static void pic2_fast_flush_chain PARM((struct pic2_info*)); ++static void pic2_fast_write_color PARM((struct pic2_info*,int)); ++static void pic2_fast_press_line2 PARM((struct pic2_info*)); ++static int pic2_fast_press_line PARM((struct pic2_info*,pixel**)); ++static int pic2_fast_saver_init PARM((struct pic2_info*,pixel**)); ++static int pic2_beta_press_line PARM((struct pic2_info*,pixel**)); ++static int pic2_beta_saver_init PARM((struct pic2_info*,pixel**)); ++static void pic2_write_data PARM((struct pic2_info*,byte*, ++ int,int,int,int,int, ++ byte*,byte*,byte*,int,int)); ++static int pic2_next_line PARM((struct pic2_info*,pixel**)); ++static int pic2_next_block PARM((struct pic2_info*)); ++static int pic2_find_block PARM((struct pic2_info*)); ++static int pic2_load_block PARM((struct pic2_info*)); ++static int pic2_save_block PARM((struct pic2_info*,pixel**, ++ int,int,int,int,char*,pixel)); ++#ifndef PIC2_IGNORE_UNUSED_FUNCTIONS ++static void pic2_read_palette PARM((struct pic2_info*, ++ byte*,byte*,byte*)); ++static void pic2_write_palette PARM((struct pic2_info*,int,int, ++ byte*,byte*,byte*)); ++#endif /* !PIC2_IGNORE_UNUSED_FUNCTIONS */ ++static byte pic2_convert_color_bits PARM((int,int,int)); ++static byte pic2_pad_color_bits PARM((int,int,int)); ++static byte pic2_reduce_color_bits PARM((int,int,int)); ++static pixel pic2_exchange_rg PARM((pixel,int)); ++static void pic2_handle_para PARM((struct pic2_info*,int)); ++static int pic2_alloc_buffer PARM((struct pic2_info*)); ++static void pic2_free_buffer PARM((struct pic2_info*)); ++static long pic2_seek_file PARM((struct pic2_info*,long,int)); ++static long pic2_tell_file PARM((struct pic2_info*)); ++static int pic2_read_file PARM((struct pic2_info*,void*,size_t)); ++static long pic2_read_long PARM((struct pic2_info*)); ++static short pic2_read_short PARM((struct pic2_info*)); ++static char pic2_read_char PARM((struct pic2_info*)); ++static int pic2_write_file PARM((struct pic2_info*,void*,size_t)); ++static int pic2_write_long PARM((struct pic2_info*,long)); ++static int pic2_write_short PARM((struct pic2_info*,int)); ++static int pic2_write_char PARM((struct pic2_info*,int)); ++static unsigned long pic2_read_bits PARM((struct pic2_info*,int)); ++static void pic2_write_bits PARM((struct pic2_info*, ++ unsigned long,int)); ++static void pic2_flush_bits PARM((struct pic2_info*)); ++static void pic2_memory_error PARM((char*,char*)); ++static void pic2_error PARM((struct pic2_info*,int)); ++static void pic2_file_error PARM((struct pic2_info*,int)); ++static void pic2_init_info PARM((struct pic2_info*)); ++static void pic2_cleanup_pic2_info PARM((struct pic2_info*,int)); ++static void pic2_cleanup_pinfo PARM((PICINFO*)); ++static void pic2_show_pic2_info PARM((struct pic2_info*)); ++static char *pic2_strncpy PARM((char*,char*,size_t)); ++static void *pic2_malloc PARM((size_t,char*)); ++static void *pic2_new PARM((size_t,char*)); ++ ++static int WritePIC2 PARM((FILE*,byte*,int,int,int, ++ byte*,byte*,byte*,int,int,char*, ++ int,int,int,int,int,char*)); ++ ++static char *pic2_id = "P2DT"; ++ ++/* Error Messages */ ++static char *pic2_msgs[] = { ++ NULL, ++#define PIC2_OPEN 1 ++ "can't open file.", ++#define PIC2_CORRUPT 2 ++ "file corrupted.", ++#define PIC2_FORMAT 3 ++ "not PIC2 format.", ++#define PIC2_DEPTH 4 ++ "bit depths not divisible by 3 are unsupported.", ++#define PIC2_TMPFILE 5 ++ "unable to create temporary filename???", ++#define PIC2_PAGE 6 ++ "couldn't load the page.", ++#define PIC2_APPEND 7 ++ "cannot append.", ++#define PIC2_WRITE 8 ++ "write failed.", ++}; ++ ++struct _form_tab { ++ char *id; ++ int (*loader_init) PARM((struct pic2_info *)); ++ int (*saver_init) PARM((struct pic2_info *, pixel **)); ++} form_tab[] = { ++ { "P2SS", pic2_arith_loader_init, pic2_arith_saver_init}, ++ { "P2SF", pic2_fast_loader_init, pic2_fast_saver_init}, ++ { "P2BM", pic2_beta_loader_init, pic2_beta_saver_init}, ++ { "P2BI", pic2_beta_loader_init, pic2_beta_saver_init}, ++}; ++#define n_form_tab (sizeof(form_tab) / sizeof(struct _form_tab)) ++#define P2SS 0 ++#define P2SF 1 ++#define P2BM 2 ++#define P2BI 3 ++ ++/* The main routine to load a PIC2 file. */ ++int LoadPIC2(fname, pinfo, quick) ++char *fname; ++PICINFO *pinfo; ++int quick; ++{ ++ int e, i, block; ++ struct pic2_info pic2; ++ ++ if (DEBUG) ++ fputs("LoadPIC2:\n", stderr); ++ ++ pic2_init_info(&pic2); ++ ++ if ((e = setjmp(pic2.jmp)) != 0){ ++ /* When an error occurs, comes here. */ ++ pic2_free_buffer(&pic2); ++ pic2_cleanup_pic2_info(&pic2, 0); ++ pic2_cleanup_pinfo(pinfo); ++ if (pic2split) ++ KillPageFiles(pic2.pagebname, pic2.pnum); ++ SetCursors(-1); ++ if (DEBUG) ++ fputs("\n", stderr); ++ return (0); ++ } ++ pic2_open_file(&pic2, fname); ++ pic2_read_header(&pic2); ++ ++ if ((i = pic2_find_block(&pic2)) == 0) ++ pic2_file_error(&pic2, PIC2_CORRUPT); ++ ++ block = 1; ++ while(i == 2) { ++ SetISTR(ISTR_WARNING, "unknown or invalid block #%d.", block); ++ i = pic2_next_block(&pic2); ++ block++; ++ } ++ ++ if (pic2split && !quick) { ++ char firstpage[512]; ++ struct stat st; ++#ifndef USE_MKSTEMP ++ int tmpfd; ++#endif ++ ++#ifndef VMS ++ sprintf(pic2.pagebname, "%s/xvpic2XXXXXX", tmpdir); ++#else ++ sprintf(pic2.pagebname, "Sys$Scratch:xvpic2XXXXXX"); ++#endif ++#ifdef USE_MKSTEMP ++ close(mkstemp(pic2.pagebname)); ++#else ++ mktemp(pic2.pagebname); ++ tmpfd = open(pic2.pagebname, O_WRONLY|O_CREAT|O_EXCL, S_IRWUSR); ++ if (tmpfd < 0) FatalError("LoadPIC2(): can't create temporary file"); ++ close(tmpfd); ++#endif ++ if (pic2.pagebname[0] == '\0') ++ pic2_error(&pic2, PIC2_TMPFILE); ++ strcat(pic2.pagebname, "."); ++ ++ sprintf(firstpage, "%s%d", pic2.pagebname, 1); ++ if (stat(firstpage, &st)) { ++ for (pic2.pnum = 1; i >= 1; pic2.pnum++) { ++ pic2_load_block(&pic2); ++ pic2_make_pagefile(&pic2, pic2.pagebname, pic2.pnum); ++ while(block++, (i = pic2_next_block(&pic2)) == 2) ++ SetISTR(ISTR_WARNING, ++ "unknown or invalid block #%d.", block); ++ } ++ pinfo->numpages = --pic2.pnum; ++ if (!LoadPIC2(firstpage, pinfo, 1)) ++ pic2_error(&pic2, PIC2_PAGE); ++ if (pic2.pnum == 1) ++ unlink(firstpage); ++ else ++ strcpy(pinfo->pagebname, pic2.pagebname); ++ } else ++ if (!LoadPIC2(fname, pinfo, 1)) ++ pic2_error(&pic2, PIC2_PAGE); ++ } else { ++ char buf[128], format[64]; ++ int j; ++ ++ pinfo->w = pic2.x_max; ++ pinfo->h = pic2.y_max; ++ pinfo->normw = pinfo->w; ++ pinfo->normh = pinfo->h; ++ pinfo->type = PIC24; ++ for (j = 0; j < n_form_tab; j++) { ++ if (xvbcmp(pic2.block->id, form_tab[j].id, (size_t) 4) == 0) ++ break; ++ } ++ pinfo->frmType = F_PIC2; ++ pinfo->colType = F_FULLCOLOR; ++ pinfo->comment = pic2.comment; ++ ++ if (pic2split) { ++ pic2_make_xvpic(&pic2, &pinfo->pic, pinfo->r, pinfo->g, pinfo->b); ++ strcpy(format, form_tab[j].id); ++ } else { ++ for (pic2.pnum = 1; i >= 1; pic2.pnum++) { ++ SetISTR(ISTR_INFO, "composing block #%d", block); ++ pic2_make_xvpic(&pic2, &pinfo->pic, ++ pinfo->r, pinfo->g, pinfo->b); ++ while(block++, (i = pic2_next_block(&pic2)) == 2) ++ SetISTR(ISTR_WARNING, ++ "unknown or invalid block #%d.", block); ++ } ++ if (--block > 1) ++ if (block != --pic2.pnum) ++ sprintf(format, "MultiBlock[%d/%d]", block, pic2.pnum); ++ else ++ sprintf(format, "MultiBlock[%d]", block); ++ else ++ strcpy(format, form_tab[j].id); ++ } ++ sprintf(buf, "PIC2(%s). %d colors (%ld bytes)", format, ++ (int) 1 << pic2.header->depth, pic2.fsize); ++ strcat(pinfo->fullInfo, buf); ++ sprintf(pinfo->shrtInfo, "%dx%d(aspect %4.2f) PIC2(%s).", ++ pinfo->w, pinfo->h, ++ (float) pic2.header->x_aspect / (float) pic2.header->y_aspect, ++ format); ++ if (!nopicadjust) ++ normaspect = (float) pic2.header->x_aspect ++ / (float) pic2.header->y_aspect; ++ } ++ pic2_cleanup_pic2_info(&pic2, 0); ++ SetCursors(-1); ++ if (DEBUG) ++ fputs("\n", stderr); ++ return (1); ++} ++ ++/* ++ * This function opens the file, and set its size. ++ */ ++static void pic2_open_file(pi, fname) ++ struct pic2_info *pi; ++ char *fname; ++{ ++ if ((pi->fp = fopen(fname, "rb")) == NULL) ++ pic2_file_error(pi, PIC2_OPEN); ++ fseek(pi->fp, (size_t) 0, SEEK_END); ++ pi->fsize = ftell(pi->fp); ++ fseek(pi->fp, (size_t) 0, SEEK_SET); ++} ++ ++/* ++ * These functions read the PIC2 header informations. ++ * pic2_read_header: ++ * reads the PIC2 header. ++ * pic2_read_block_header1: ++ * reads the id number of block header and the size of block. ++ * pic2_read_block_header2: ++ * reads the rest of block header. ++ */ ++static void pic2_read_header(pi) ++struct pic2_info *pi; ++{ ++ long s_comment; ++ ++ pi->mode = PIC2_READ_MODE; ++ ++ /* read header image */ ++ pic2_read_file(pi, pi->header->magic, 4); ++ pic2_read_file(pi, pi->header->name, 18); ++ pic2_read_file(pi, pi->header->subtitle, 8); ++ pic2_read_file(pi, pi->header->crlf0, 2); ++ pic2_read_file(pi, pi->header->title, 30); ++ pic2_read_file(pi, pi->header->crlf1, 2); ++ pic2_read_file(pi, pi->header->saver, 30); ++ pic2_read_file(pi, pi->header->crlf2, 2); ++ pic2_read_file(pi, pi->header->eof, 1); ++ pic2_read_file(pi, pi->header->reserve0, 1); ++ pi->header->flag = pic2_read_short(pi); ++ pi->header->no = pic2_read_short(pi); ++ pi->header->time = pic2_read_long(pi); ++ pi->header->size = pic2_read_long(pi); ++ pi->header->depth = pic2_read_short(pi); ++ pi->header->x_aspect = pic2_read_short(pi); ++ pi->header->y_aspect = pic2_read_short(pi); ++ pi->header->x_max = pic2_read_short(pi); ++ pi->header->y_max = pic2_read_short(pi); ++ pi->header->reserve1 = pic2_read_long(pi); ++ ++ /* check magic number */ ++ if (strncmp(pi->header->magic, pic2_id, (size_t) 4) != 0) ++ pic2_error(pi, PIC2_FORMAT); ++ ++ /* read palette data, if exists */ ++ if (pi->header->flag & 1) { ++ pi->pal_bits = pic2_read_char(pi); ++ pi->n_pal = pic2_read_short(pi); ++ pic2_read_file(pi, pi->pal, (size_t) (pi->n_pal * 3)); ++ } ++ ++ /* read comments */ ++ s_comment = pi->header->size - pic2_tell_file(pi); ++ pi->comment = pic2_new(s_comment + 1, "pic2_read_header"); ++ pic2_read_file(pi, pi->comment, (size_t) s_comment); ++ pi->comment[s_comment] = '\0'; ++ ++ pi->x_max = pi->header->x_max; ++ pi->y_max = pi->header->y_max; ++ ++ /* set initial block point */ ++ pi->next_pos = pic2_tell_file(pi); ++} ++ ++static void pic2_read_block_header1(pi) ++struct pic2_info *pi; ++{ ++ pic2_read_file(pi, pi->block->id, 4); ++ pi->block->size = pic2_read_long(pi); ++} ++ ++static void pic2_read_block_header2(pi) ++struct pic2_info *pi; ++{ ++ pi->block->flag = pic2_read_short(pi); ++ pi->block->x_wid = pic2_read_short(pi); ++ pi->block->y_wid = pic2_read_short(pi); ++ pi->block->x_offset = pic2_read_short(pi); ++ pi->block->y_offset = pic2_read_short(pi); ++ pi->block->opaque = pic2_read_long(pi); ++ pi->block->reserve = pic2_read_long(pi); ++} ++ ++/* ++ * These functions are arithmetic pic2 format extractor. ++ */ ++static short pic2_arith_decode_bit(pi, c) ++struct pic2_info *pi; ++int c; ++{ ++ unsigned short pp; ++ ++ pp = pi->mulu_tab[(pi->aa & 0x7f00) / 2 + c]; ++ if (pi->dd >= (int) pp) { ++ pi->dd -= pp; ++ pi->aa -= pp; ++ ++ while ((short) pi->aa >= 0) { ++ pi->dd *= 2; ++ if (pic2_read_bits(pi, 1)) ++ pi->dd++; ++ pi->aa *= 2; ++ } ++ return (1); ++ } else { ++ pi->aa = pp; ++ ++ while ((short) pi->aa >= 0) { ++ pi->dd *= 2; ++ if (pic2_read_bits(pi, 1)) ++ pi->dd++; ++ pi->aa *= 2; ++ } ++ return (0); ++ } ++} ++ ++static short pic2_arith_decode_nn(pi, c) ++struct pic2_info *pi; ++int c; ++{ ++ int n; ++ ++ if (pic2_arith_decode_bit(pi, c)) { ++ /* n < 1 */ ++ n = 0; ++ } else if (pic2_arith_decode_bit(pi, c + 1)) { ++ /* n < 1 + 2 */ ++ n = 1; ++ if (pic2_arith_decode_bit(pi, c + 8)) ++ n += 1; ++ } else if (pic2_arith_decode_bit(pi, c + 2)) { ++ /* n < 1 + 2 + 4 */ ++ n = 1 + 2; ++ if (pic2_arith_decode_bit(pi, c + 8)) ++ n += 1; ++ if (pic2_arith_decode_bit(pi, c + 9)) ++ n += 2; ++ } else if (pic2_arith_decode_bit(pi, c + 3)) { ++ /* n < 1 + 2 + 4 + 8 */ ++ n = 1 + 2 + 4; ++ if (pic2_arith_decode_bit(pi, c + 8)) ++ n += 1; ++ if (pic2_arith_decode_bit(pi, c + 9)) ++ n += 2; ++ if (pic2_arith_decode_bit(pi, c + 10)) ++ n += 4; ++ } else if (pic2_arith_decode_bit(pi, c + 4)) { ++ /* n < 1 + 2 + 4 + 8 + 16 */ ++ n = 1 + 2 + 4 + 8; ++ if (pic2_arith_decode_bit(pi, c + 8)) ++ n += 1; ++ if (pic2_arith_decode_bit(pi, c + 9)) ++ n += 2; ++ if (pic2_arith_decode_bit(pi, c + 10)) ++ n += 4; ++ if (pic2_arith_decode_bit(pi, c + 11)) ++ n += 8; ++ } else if (pic2_arith_decode_bit(pi, c + 5)) { ++ /* n < 1 + 2 + 4 + 8 + 16 + 32 */ ++ n = 1 + 2 + 4 + 8 + 16; ++ if (pic2_arith_decode_bit(pi, c + 8)) ++ n += 1; ++ if (pic2_arith_decode_bit(pi, c + 9)) ++ n += 2; ++ if (pic2_arith_decode_bit(pi, c + 10)) ++ n += 4; ++ if (pic2_arith_decode_bit(pi, c + 11)) ++ n += 8; ++ if (pic2_arith_decode_bit(pi, c + 12)) ++ n += 16; ++ ++ } else if (pic2_arith_decode_bit(pi, c + 6)) { ++ /* n < 1 + 2 + 4 + 8 + 16 + 32 + 64 */ ++ n = 1 + 2 + 4 + 8 + 16 + 32; ++ if (pic2_arith_decode_bit(pi, c + 8)) ++ n += 1; ++ if (pic2_arith_decode_bit(pi, c + 9)) ++ n += 2; ++ if (pic2_arith_decode_bit(pi, c + 10)) ++ n += 4; ++ if (pic2_arith_decode_bit(pi, c + 11)) ++ n += 8; ++ if (pic2_arith_decode_bit(pi, c + 12)) ++ n += 16; ++ if (pic2_arith_decode_bit(pi, c + 13)) ++ n += 32; ++ ++ } else if (pic2_arith_decode_bit(pi, c + 7)) { ++ /* n < 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 */ ++ n = 1 + 2 + 4 + 8 + 16 + 32 + 64; ++ if (pic2_arith_decode_bit(pi, c + 8)) ++ n += 1; ++ if (pic2_arith_decode_bit(pi, c + 9)) ++ n += 2; ++ if (pic2_arith_decode_bit(pi, c + 10)) ++ n += 4; ++ if (pic2_arith_decode_bit(pi, c + 11)) ++ n += 8; ++ if (pic2_arith_decode_bit(pi, c + 12)) ++ n += 16; ++ if (pic2_arith_decode_bit(pi, c + 13)) ++ n += 32; ++ if (pic2_arith_decode_bit(pi, c + 14)) ++ n += 64; ++ ++ } else { ++ n = 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128; ++ } ++ return (n); ++} ++ ++static void pic2_arith_expand_chain(pi, x, y, cc) ++struct pic2_info *pi; ++int x, y; ++pixel cc; ++{ ++ static const unsigned short c_tab[] = { ++ 80 + 6 * 5, /* -5 */ ++ 80 + 6 * 4, ++ 80 + 6 * 3, ++ 80 + 6 * 2, ++ 80 + 6 * 1, ++ 80 + 6 * 0, /* 0 */ ++ 80 + 6 * 0, /* 1 */ ++ }; ++ unsigned short b; ++ ++ b = c_tab[pi->flag_now[x] + 5]; ++ if (!pic2_arith_decode_bit(pi, b++)) { ++ if (pic2_arith_decode_bit(pi, b++)) { /* down */ ++ pi->vram_next[x ] = cc; ++ pi->flag_next[x ] = -1; ++ } else if (pic2_arith_decode_bit(pi, b++)) { /* left */ ++ pi->vram_next[x - 1] = cc; ++ pi->flag_next[x - 1] = -2; ++ } else if (pic2_arith_decode_bit(pi, b++)) { /* right */ ++ pi->vram_next[x + 1] = cc; ++ pi->flag_next[x + 1] = -3; ++ } else if (pic2_arith_decode_bit(pi, b++)) { /* left2 */ ++ pi->vram_next[x - 2] = cc; ++ pi->flag_next[x - 2] = -4; ++ } else { /* right2 */ ++ pi->vram_next[x + 2] = cc; ++ pi->flag_next[x + 2] = -5; ++ } ++ } ++} ++ ++static short pic2_arith_get_number(pi, c, bef) ++struct pic2_info *pi; ++int c, bef; ++{ ++ unsigned short n; ++ byte maxcol; ++ ++ maxcol = 0xff >> (8 - pi->header->depth / 3); ++ ++ n = pic2_arith_decode_nn(pi, c); ++ if (bef > ((int) maxcol >> 1)) { ++ if (n > ((int) maxcol - bef) * 2) ++ n = maxcol - n; ++ else if (n & 1) ++ n = n / 2 + bef + 1; ++ else ++ n = bef - n / 2; ++ } else { ++ if ((int) n > (bef * 2)) ++ n = n; ++ else if (n & 1) ++ n = n / 2 + bef + 1; ++ else ++ n = bef - n / 2; ++ } ++ return (n); ++} ++ ++static pixel pic2_arith_read_color(pi, x) ++struct pic2_info *pi; ++int x; ++{ ++ pixel c1, c2, cc; ++ unsigned short i, j, k, m; ++ short r, g, b, r0, g0, b0; ++ short colbits; ++ pixel rmask, gmask, bmask; ++ byte maxcol; ++ ++ colbits = pi->header->depth / 3; ++ rmask = (0xff >> (8 - colbits)) << (colbits * 2); ++ gmask = (0xff >> (8 - colbits)) << colbits; ++ bmask = (0xff >> (8 - colbits)); ++ maxcol = (byte) bmask; ++ ++ c1 = pi->vram_prev[x]; ++ k = ((c1 >> ((colbits - 3) * 3)) & 0x1c0) ++ | ((c1 >> ((colbits - 3) * 2)) & 0x038) ++ | ((c1 >> (colbits - 3) ) & 0x007); ++ if (colbits == 5) ++ k = pic2_exchange_rg(k, 3); ++ ++ if (pic2_arith_decode_bit(pi, pi->cache_hit_c)) { /* ouch */ ++ pi->cache_hit_c = 16; ++ ++ c2 = pi->vram_now[x - 1]; ++ r = ((c1 & rmask) + (c2 & rmask)) >> (colbits * 2 + 1); ++ g = ((c1 & gmask) + (c2 & gmask)) >> (colbits + 1); ++ b = ((c1 & bmask) + (c2 & bmask)) >> ( 1); ++ ++ g0 = pic2_arith_get_number(pi, 32, g); ++ r = r + g0 - g; ++ if (r > (short) maxcol) ++ r = maxcol; ++ else if (r < 0) ++ r = 0; ++ ++ b = b + g0 - g; ++ if (b > (short) maxcol) ++ b = maxcol; ++ else if (b < 0) ++ b = 0; ++ ++ r0 = pic2_arith_get_number(pi, 48, r); ++ b0 = pic2_arith_get_number(pi, 64, b); ++ ++ pi->cache_pos[k] = j = (pi->cache_pos[k] - 1) & (PIC2_ARITH_CACHE - 1); ++ pi->cache[k][j] = cc = (r0 << (colbits * 2)) | (g0 << colbits) | b0; ++ } else { ++ pi->cache_hit_c = 15; ++ ++ j = pic2_arith_decode_nn(pi, 17); ++ m = pi->cache_pos[k]; ++ i = (m + j / 2) & (PIC2_ARITH_CACHE - 1); ++ j = (m + j) & (PIC2_ARITH_CACHE - 1); ++ ++ cc = pi->cache[k][j]; ++ pi->cache[k][j] = pi->cache[k][i]; ++ pi->cache[k][i] = pi->cache[k][m]; ++ pi->cache[k][m] = cc; ++ } ++ return (cc); ++} ++ ++static int pic2_arith_expand_line(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ int ymax; ++ int x, xw; ++ pixel cc; ++ ++ pic2_handle_para(pi, 0); ++ ++ xw = pi->block->x_wid; ++ ymax = pi->block->y_wid - 1; ++ ++ if (pi->ynow > ymax) ++ return (-2); /* end */ ++ ++ /* set right end of previous line before left end of current line. */ ++ if (pi->ynow == 0) { ++ cc = 0; ++ } else ++ cc = pi->vram_prev[xw - 1]; ++ pi->vram_now[-1] = cc; ++ ++ /* clear flag for change point */ ++ xvbzero((char *) pi->flag_next, xw * sizeof(pi->flag_next[0])); ++ ++ /* clear flag for position probability space */ ++ xvbzero((char *) pi->flag2_next2, xw * sizeof(pi->flag2_next2[0])); ++ ++ for (x = 0; x < xw; x++) { ++ if (pi->flag_now[x] < 0) { ++ cc = pi->vram_now[x]; ++ if (pi->ynow < ymax) ++ pic2_arith_expand_chain(pi, x, pi->ynow, cc); ++ } else if (pic2_arith_decode_bit(pi, pi->flag2_now[x])) { ++ /* ajust probability space around of change point */ ++ pi->flag2_now [x + 1]++; ++ pi->flag2_now [x + 2]++; ++ pi->flag2_next [x - 1]++; ++ pi->flag2_next [x ]++; ++ pi->flag2_next [x + 1]++; ++ pi->flag2_next2[x - 1]++; ++ pi->flag2_next2[x ]++; ++ pi->flag2_next2[x + 1]++; ++ ++ pi->vram_now[x] = cc = pic2_arith_read_color(pi, x); ++ if (pi->ynow < ymax) ++ pic2_arith_expand_chain(pi, x, pi->ynow, cc); ++ } else ++ pi->vram_now[x] = cc; ++ } ++ if (line != NULL) ++ *line = pi->vram_now; ++ pi->ynow++; ++ ++ pic2_handle_para(pi, 1); ++ ++ return (pi->ynow - 1); ++} ++ ++static int pic2_arith_loader_init(pi) ++struct pic2_info *pi; ++{ ++ unsigned short p2b[256]; ++ int i, xw; ++ ++ pi->ynow = 0; ++ ++ /* check the color depth */ ++ if (pi->header->depth % 3) ++ pic2_error(pi, PIC2_DEPTH); ++ ++ /* set function for extract next line */ ++ pi->next_line = pic2_arith_expand_line; ++ ++ /* clear cache and flags */ ++ xw = pi->block->x_wid; ++ xvbzero((char *) pi->cache, 8 * 8 * 8 * sizeof(pi->cache[0])); ++ xvbzero((char *) pi->cache_pos, 8 * 8 * 8 * sizeof(pi->cache_pos[0])); ++ ++ xvbzero((char *) pi->flag_now, xw * sizeof(pi->flag_now[0])); ++ xvbzero((char *) pi->flag2_now, 8 + xw * sizeof(pi->flag2_now[0])); ++ xvbzero((char *) pi->flag2_next, 8 + xw * sizeof(pi->flag2_next[0])); ++ ++ /* go to picture data field */ ++ pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET); ++ ++ /* clear bit field marker */ ++ pi->bs.rest = 0; ++ pi->bs.cur = 0; ++ ++ /* read probability table */ ++ for (i = 0; i < PIC2_ARITH_CONTEXT; i++) ++ p2b[i] = pic2_read_short(pi); ++ ++ /* make multiplication table */ ++ for (i = 0; i < 16384; i++) { ++ pi->mulu_tab[i] = (long) (i / 128 + 128) * (int) p2b[i & 127] / 256; ++ if (pi->mulu_tab[i] == 0) pi->mulu_tab[i] = 1; ++ } ++ /* initialize some valuables */ ++ pi->aa = 0xffff; ++ pi->dd = 0; ++ for (i = 0; i < 16; i++) { ++ pi->dd *= 2; ++ if (pic2_read_bits(pi, 1)) ++ pi->dd |= 1; ++ } ++ pi->cache_hit_c = 16; ++ ++ return (0); ++} ++ ++/* ++ * These functions are fast pic2 compression extractor. ++ */ ++static int pic2_fast_read_length(pi) ++struct pic2_info *pi; ++{ ++ int a; ++ ++ a = 0; ++ while (pic2_read_bits(pi, 1)) { ++ a++; ++ } ++ if (a == 0) ++ return (0); ++ return (pic2_read_bits(pi, a) + (1 << a) - 1); ++} ++ ++static void pic2_fast_expand_chain(pi, x, cc) ++struct pic2_info *pi; ++int x; ++pixel cc; ++{ ++ if (pic2_read_bits(pi, 1) != 0) { ++ if (pic2_read_bits(pi, 1) != 0) { /* down */ ++ pi->vram_next[x] = cc; ++ pi->flag_next[x] = -1; ++ } else if (pic2_read_bits(pi, 1) != 0) { ++ if (pic2_read_bits(pi, 1) == 0) { /* left2down */ ++ pi->vram_next[x - 2] = cc; ++ pi->flag_next[x - 2] = -1; ++ } else { /* left1down */ ++ pi->vram_next[x - 1] = cc; ++ pi->flag_next[x - 1] = -1; ++ } ++ } else { ++ if (pic2_read_bits(pi, 1) == 0) { /* right2down */ ++ pi->vram_next[x + 2] = cc; ++ pi->flag_next[x + 2] = -1; ++ } else { /* left1down */ ++ pi->vram_next[x + 1] = cc; ++ pi->flag_next[x + 1] = -1; ++ } ++ } ++ } ++} ++ ++static pixel pic2_fast_read_color(pi, bc) ++struct pic2_info *pi; ++pixel bc; ++{ ++ pixel cc; ++ unsigned short j, k, m; ++ short depth, colbits; ++ pixel (*cache)[PIC2_FAST_CACHE]; ++ ++ depth = pi->header->depth; ++ colbits = depth / 3; ++ cache = (pixel (*)[PIC2_FAST_CACHE]) pi->cache; ++ ++ bc = pic2_exchange_rg(bc, colbits); ++ k = pic2_shift_bits(bc, 8 - depth); ++ if (pic2_read_bits(pi, 1) == 0) { ++ pi->cache_pos[k] = m = (pi->cache_pos[k] - 1) & (PIC2_FAST_CACHE - 1); ++ cc = pic2_read_bits(pi, depth); ++ cc = pic2_exchange_rg(cc, colbits); ++ cache[k][m] = cc; ++ } else { ++ j = pic2_read_bits(pi, 6); /* 6= log2(PIC2_FAST_CACHE) */ ++ m = pi->cache_pos[k]; ++ cc = cache[k][(m + j) & (PIC2_FAST_CACHE - 1)]; ++ } ++ return (cc); ++} ++ ++static int pic2_fast_expand_line(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ int ymax; ++ int x, xw; ++ pixel cc; ++ ++ pic2_handle_para(pi, 0); ++ ++ xw = pi->block->x_wid; ++ ymax = pi->block->y_wid - 1; ++ ++ if (pi->ynow > ymax) ++ return (-2); ++ ++ if (pi->ynow == 0) { ++ pi->dd = 0; ++ pi->aa = pic2_fast_read_length(pi); ++ if (pi->aa == 1023) ++ pi->dd = 1023; ++ else if (pi->aa > 1023) ++ pi->aa--; ++ cc = 0; ++ } else ++ cc = pi->vram_prev[xw - 1]; ++ ++ xvbzero((char *) pi->flag_next, xw * sizeof(pi->flag_next[0])); ++ ++ for (x = 0; x < xw; x++) { ++ if (pi->dd > 0) { ++ if (pi->flag_now[x] < 0) { /* on chain ? */ ++ cc = pi->vram_now[x]; ++ pic2_fast_expand_chain(pi, x, cc); ++ if (--pi->dd == 0) { ++ pi->aa = pic2_fast_read_length(pi); ++ if (pi->aa == 1023) ++ pi->dd = 1023; ++ else if (pi->aa > 1023) ++ pi->aa--; ++ } ++ } else ++ pi->vram_now[x] = cc; ++ } else { ++ if (pi->flag_now[x] < 0) { /* on chain ? */ ++ cc = pi->vram_now[x]; ++ pic2_fast_expand_chain(pi, x, cc); ++ } else if (--pi->aa < 0) { ++ cc = pi->vram_now[x] = pic2_fast_read_color(pi, cc); ++ pic2_fast_expand_chain(pi, x, cc); ++ pi->aa = pic2_fast_read_length(pi); ++ if (pi->aa == 1023) ++ pi->dd = 1023; ++ else if (pi->aa > 1023) ++ pi->aa--; ++ } else ++ pi->vram_now[x] = cc; ++ } ++ } ++ if (line != NULL) ++ *line = pi->vram_now; ++ pi->ynow++; ++ ++ pic2_handle_para(pi, 1); ++ ++ return (pi->ynow - 1); ++} ++ ++static int pic2_fast_loader_init(pi) ++struct pic2_info *pi; ++{ ++ int xw; ++ ++ pi->ynow = 0; ++ ++ /* check the color depth */ ++ if (pi->header->depth % 3) ++ pic2_error(pi, PIC2_DEPTH); ++ ++ /* set function for extract next line */ ++ pi->next_line = pic2_fast_expand_line; ++ ++ /* clear cache and flags */ ++ xw = pi->block->x_wid; ++ xvbzero((char *) pi->cache, sizeof(pi->cache[0]) * 256); ++ xvbzero((char *) pi->cache_pos, sizeof(pi->cache_pos[0]) * 8 * 8 * 8); ++ xvbzero((char *) pi->flag_now, (xw + 8) * sizeof(pi->flag_now[0])); ++ xvbzero((char *) pi->flag_next, (xw + 8) * sizeof(pi->flag_next[0])); ++ ++ /* go to picture data field */ ++ pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET); ++ ++ /* clear bit field marker */ ++ pi->bs.rest = 0; ++ pi->bs.cur = 0; ++ ++ return (0); ++} ++ ++/* ++ * These functions are beta pic2 format extractor. ++ */ ++static int pic2_beta_expand_line(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ int i, xw, ymax; ++ byte a, b, c, *p; ++ pixel *pc; ++ short depth, pixbyte, colbits; ++ ++ depth = pi->header->depth; ++ pixbyte = depth / 8 + ((depth % 8) > 0); ++ colbits = depth / 3; ++ ++ xw = pi->block->x_wid; ++ ymax = pi->block->y_wid - 1; ++ ++ if (pi->ynow > ymax) ++ return (-2); /* end */ ++ ++ pc = pi->vram_now; ++ p = (byte *) pi->vram_prev; ++ if (pixbyte == 3) { ++ pic2_read_file(pi, pi->vram_prev, (size_t) (xw * pixbyte)); ++ for (i = 0; i < xw; i++, pc++) { ++ a = *p++; ++ b = *p++; ++ c = *p++; ++ *pc = ((pixel) a << 16) | ((pixel) b << 8) | (pixel) c; ++ } ++ } else if (pixbyte == 2) { ++ pic2_read_file(pi, pi->vram_prev, (size_t) (xw * 2)); ++ if (strncmp(pi->block->id, "P2BM", 4) == 0) { ++ for (i = 0; i < xw; i++, pc++) { ++ a = *p++; ++ b = *p++; ++ *pc = ((pixel) a << 8) | (pixel) b; ++ if (colbits == 5) { ++ *pc >>= 1; ++ *pc = pic2_exchange_rg(*pc, colbits); ++ } ++ } ++ } else { ++ for (i = 0; i < xw; i++, pc++) { ++ a = *p++; ++ b = *p++; ++ *pc = ((pixel) b << 8) | (pixel) a; ++ if (colbits == 5) { ++ *pc >>= 1; ++ *pc = pic2_exchange_rg(*pc, colbits); ++ } ++ } ++ } ++ } else { ++ pic2_read_file(pi, pi->vram_prev, (size_t) xw); ++ for (i = 0; i < xw; i++) ++ *pc++ = *p++; ++ } ++ if (line != NULL) ++ *line = pi->vram_now; ++ ++ pc = pi->vram_prev; ++ pi->vram_prev = pi->vram_now; ++ pi->vram_now = pi->vram_next; ++ pi->vram_next = pc; ++ ++ pi->ynow++; ++ return (pi->ynow - 1); ++} ++ ++static int pic2_beta_loader_init(pi) ++struct pic2_info *pi; ++{ ++ pi->ynow = 0; ++ pi->next_line = pic2_beta_expand_line; ++ pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET); ++ return (0); ++} ++ ++/* ++ * Make a picture from the expanded data. ++ */ ++static void pic2_make_xvpic(pi, xp, rp, gp, bp) ++struct pic2_info *pi; ++byte **xp, *rp, *gp, *bp; ++{ ++ int line, i; ++ pixel *linep, opaque; ++ short colbits; ++ byte colmask; ++ ++ if (*xp == NULL) ++ *xp = pic2_new((size_t) pi->x_max * pi->y_max * 3, "pic2_make_xvpic"); // GRR POSSIBLE OVERFLOW / FIXME ++ ++ if (pi->block->flag & 1) ++ opaque = pi->block->opaque; ++ else ++ opaque = 0xffffffff; ++ ++ colbits = pi->header->depth / 3; ++ colmask = 0xff >> (8 - colbits); ++ ++ line = pic2_load_block(pi); ++ for (;;) { ++ int pic_idx; ++ ++ line = pic2_next_line(pi, &linep); ++ if (line < 0) ++ break; ++ pic_idx = ((line + pi->block->y_offset) * pi->x_max ++ + pi->block->x_offset) * 3; ++ ++ for (i = 0; i < pi->block->x_wid; i++, linep++) { ++ byte r, g, b; ++ ++ if (*linep != opaque) { ++ r = ((*linep >> (colbits * 2)) & colmask); ++ r = pic2_convert_color_bits(r, colbits, 8); ++ g = ((*linep >> colbits ) & colmask); ++ g = pic2_convert_color_bits(g, colbits, 8); ++ b = ( *linep & colmask); ++ b = pic2_convert_color_bits(b, colbits, 8); ++ (*xp)[pic_idx++] = r; ++ (*xp)[pic_idx++] = g; ++ (*xp)[pic_idx++] = b; ++ } else ++ pic_idx += 3; ++ ++ WaitCursor(); ++ } ++ } ++} ++ ++/* ++ * This function splits a multiblock PIC2 file into several pages. ++ */ ++static void pic2_make_pagefile(pi, pagebname, pnum) ++struct pic2_info *pi; ++char *pagebname; ++int pnum; ++{ ++ struct pic2_info pic2; ++ FILE *fp; ++ char pagefile[64], *buf; ++ size_t imagesize; ++ ++ sprintf(pagefile, "%s%d", pagebname, pnum); ++ if ((fp = fopen(pagefile, "wb")) == NULL) ++ pic2_error(pi, PIC2_WRITE); ++ ++ xvbcopy((char *) pi, (char *) &pic2, sizeof(struct pic2_info)); ++ pic2.fp = fp; ++ ++ pic2_write_header1(&pic2); ++ ++ pic2_write_block_header(&pic2); ++ ++ imagesize = pi->block->size - PIC2_BLOCK_HEADER_SIZE; ++ buf = (char *) pic2_malloc(imagesize, "pic2_make_pagefile"); ++ ++ pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET); ++ if (fread(buf, (size_t) 1, imagesize, pi->fp) < imagesize) { ++ free(buf); ++ pic2_file_error(pi, PIC2_CORRUPT); ++ } ++ if (fwrite(buf, (size_t) 1, imagesize, fp) < imagesize) { ++ free(buf); ++ pic2_error(pi, PIC2_WRITE); ++ } ++ free(buf); ++ ++ pic2.next_pos = pic2_tell_file(&pic2); ++ pic2_write_header2(&pic2); ++ ++ fclose(fp); ++} ++ ++/* The main routine to save a PIC2 file. */ ++static int WritePIC2(fp, pic0, ptype, w, h, rmap, gmap, bmap, numcols, ++ colorstyle, fname, type, depth, x_offset, y_offset, ++ append, comment) ++FILE *fp; ++byte *pic0; ++int ptype, w, h; ++byte *rmap, *gmap, *bmap; ++int numcols, colorstyle; ++char *fname; ++int type, depth; ++int x_offset, y_offset; ++int append; ++char *comment; ++{ ++ struct pic2_info pic2; ++ char creator[256], title[256], saver[256]; ++ int e; ++ ++ if (DEBUG) ++ fputs("WritePIC2:\n", stderr); ++ ++ pic2_init_info(&pic2); ++ pic2.fp = fp; ++ pic2.writing_grey = (colorstyle == F_GREYSCALE); ++ ++ if ((e = setjmp(pic2.jmp)) != 0){ ++ /* When an error occurs while writing, comes here. */ ++ pic2_free_buffer(&pic2); ++ pic2_cleanup_pic2_info(&pic2, 1); ++ SetCursors(-1); ++ if (DEBUG) ++ fputs("\n", stderr); ++ return (-1); ++ } ++ sprintf(creator, "XV Version %s", VERSTR); ++ pic2_strncpy(title, comment, 30); ++ sprintf(saver, "XV %s/UNIX/Bradley", VERSTR); ++ ++ if (!append) { ++ pic2_setup_pic2_info(&pic2, creator, fname, title, saver, ++ 0, depth, 1, 1, w, h, comment); ++ pic2_write_header1(&pic2); ++ } else { ++ pic2_read_header(&pic2); ++ pic2_append(&pic2); ++ free(pic2.comment); ++ pic2_setup_pic2_info(&pic2, creator, fname, title, saver, ++ 0, depth, 1, 1, w, h, comment); ++ } ++ ++ pic2_write_data(&pic2, pic0, ptype, x_offset, y_offset, w, h, ++ rmap, gmap, bmap, type, depth); ++ pic2_write_header2(&pic2); ++ ++ pic2_cleanup_pic2_info(&pic2, 1); ++ SetCursors(-1); ++ if (DEBUG) ++ fputs("\n", stderr); ++ return (0); ++} ++ ++/* ++ * This function initializes pic2_info. ++ */ ++static void pic2_setup_pic2_info(pi, name, fname, title, saver, no, depth, ++ x_aspect, y_aspect, x_max, y_max, comment) ++struct pic2_info *pi; ++char *name, *fname, *title, *saver; ++int no, depth; ++int x_aspect, y_aspect; ++int x_max, y_max; ++char *comment; ++{ ++ char basename[256], *suffix; ++ ++ pi->mode = PIC2_WRITE_MODE; ++ ++ /* set magic number */ ++ strncpy(pi->header->magic, pic2_id, 4); ++ ++ /* set creator's name */ ++ pic2_strncpy(pi->header->name, (char *) name, 18); ++ ++ /* set title and subtitle */ ++ pic2_strncpy(pi->header->title, (char *) title, 30); ++ strcpy(basename, BaseName(fname)); ++ suffix = (char *) rindex(basename, '.'); ++ if (suffix) { ++ suffix++; ++ if (!strcmp(suffix, "p2") || !strcmp(suffix, "P2")) ++ *(suffix - 1) = '\0'; ++ } ++ pic2_strncpy(pi->header->subtitle, basename, 8); ++ ++ /* set saver */ ++ pic2_strncpy(pi->header->saver, saver, 30); ++ ++ /* set picture number */ ++ pi->header->no = no; ++ ++ /* import comment */ ++ pi->comment = comment; ++ ++ /* set some picture's info */ ++ pi->header->depth = depth; ++ pi->header->x_aspect = x_aspect; ++ pi->header->y_aspect = y_aspect; ++ pi->header->x_max = x_max; ++ pi->header->y_max = y_max; ++ ++ /* set some gaps */ ++ pi->header->crlf0[0] = pi->header->crlf1[0] = pi->header->crlf2[0] = 0x0d; ++ pi->header->crlf0[1] = pi->header->crlf1[1] = pi->header->crlf2[1] = 0x0a; ++ ++ pi->header->eof[0] = 0x1a; ++ pi->header->reserve0[0] = 0; ++ pi->header->reserve1 = 0; ++ ++ /* set palettes */ ++ if (pi->n_pal > 0) ++ pi->header->flag = 1; ++ else ++ pi->header->flag = 0; ++} ++ ++/* ++ * This function appends to existing pic2 file. ++ */ ++static void pic2_append(pi) ++struct pic2_info *pi; ++{ ++ int block; ++ ++ block = pic2_find_block(pi); ++ while (block > 0) ++ block = pic2_next_block(pi); ++ ++ if (block != 0) ++ pic2_error(pi, PIC2_APPEND); ++} ++ ++/* ++ * These functions write the PIC2 header. ++ * pic2_write_header1: ++ * write palette data and comment. ++ * pic2_write_header2: ++ * write the terminate block and rest header. ++ * pic2_write_block_header: ++ * write the block header. ++ */ ++static void pic2_write_header1(pi) ++struct pic2_info *pi; ++{ ++ char *comment; ++ ++ /* seek to block start position */ ++ pic2_seek_file(pi, PIC2_HEADER_SIZE, SEEK_SET); ++ ++ /* write palette */ ++ if (pi->n_pal > 0) { ++ pic2_write_char(pi, pi->pal_bits); ++ pic2_write_short(pi, pi->n_pal); ++ pic2_write_file(pi, pi->pal, (size_t) (pi->n_pal * 3)); ++ } ++ /* save comment */ ++ comment = pi->comment; ++ if (pi->comment != NULL) { ++ for (comment = pi->comment; *comment; comment++) { ++ if (*comment == '\n') { ++ pic2_write_char(pi, '\r'); ++ pic2_write_char(pi, '\n'); ++ } else if (*comment != '\r') ++ pic2_write_char(pi, *comment); ++ } ++ pic2_write_char(pi, 0); ++ } ++ /* set the next block position */ ++ pi->next_pos = pic2_tell_file(pi); ++ pi->header->size = pi->next_pos; ++} ++ ++static void pic2_write_header2(pi) ++struct pic2_info *pi; ++{ ++ pic2_seek_file(pi, pi->next_pos, SEEK_SET); ++ ++ /* write terminate block */ ++ pic2_write_long(pi, 0); ++ pic2_write_long(pi, 0); ++ ++ /* set some header information */ ++ if (pi->header->x_max < pi->x_max) ++ pi->header->x_max = pi->x_max; ++ if (pi->header->y_max < pi->x_max) ++ pi->header->y_max = pi->y_max; ++ ++ pi->header->time = time(NULL); ++ pic2_seek_file(pi, 0, SEEK_SET); ++ ++ /* write header image */ ++ pic2_write_file(pi, pi->header->magic, 4); ++ pic2_write_file(pi, pi->header->name, 18); ++ pic2_write_file(pi, pi->header->subtitle, 8); ++ pic2_write_file(pi, pi->header->crlf0, 2); ++ pic2_write_file(pi, pi->header->title, 30); ++ pic2_write_file(pi, pi->header->crlf1, 2); ++ pic2_write_file(pi, pi->header->saver, 30); ++ pic2_write_file(pi, pi->header->crlf2, 2); ++ pic2_write_file(pi, pi->header->eof, 1); ++ pic2_write_file(pi, pi->header->reserve0, 1); ++ pic2_write_short(pi, pi->header->flag); ++ pic2_write_short(pi, pi->header->no); ++ pic2_write_long(pi, pi->header->time); ++ pic2_write_long(pi, pi->header->size); ++ pic2_write_short(pi, pi->header->depth); ++ pic2_write_short(pi, pi->header->x_aspect); ++ pic2_write_short(pi, pi->header->y_aspect); ++ pic2_write_short(pi, pi->header->x_max); ++ pic2_write_short(pi, pi->header->y_max); ++ pic2_write_long(pi, pi->header->reserve1); ++} ++ ++static void pic2_write_block_header(pi) ++struct pic2_info *pi; ++{ ++ pic2_write_file(pi, pi->block->id, 4); ++ pic2_write_long(pi, pi->block->size); ++ pic2_write_short(pi, pi->block->flag); ++ pic2_write_short(pi, pi->block->x_wid); ++ pic2_write_short(pi, pi->block->y_wid); ++ pic2_write_short(pi, pi->block->x_offset); ++ pic2_write_short(pi, pi->block->y_offset); ++ pic2_write_long(pi, pi->block->opaque); ++ pic2_write_long(pi, pi->block->reserve); ++} ++ ++/* ++ * These functions implement the arithmetic-format compressor. ++ */ ++#define pic2_arith_write_one_bit(pi) (pi->bs.bits++) ++ ++static void pic2_arith_write_zero_bit(pi) ++struct pic2_info *pi; ++{ ++ if (pi->bs.zero) ++ pic2_write_bits(pi, 0, 1); ++ ++ while (pi->bs.bits--) ++ pic2_write_bits(pi, 1, 1); ++ ++ pi->bs.bits = 0; ++ pi->bs.zero = 1; ++} ++ ++static void pic2_arith_flush_bit_buf(pi) ++struct pic2_info *pi; ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) { ++ if (pi->cc & 0x8000) ++ pic2_arith_write_one_bit(pi); ++ else ++ pic2_arith_write_zero_bit(pi); ++ pi->cc <<= 1; ++ } ++ pic2_arith_write_zero_bit(pi); ++ pic2_flush_bits(pi); ++} ++ ++static void pic2_arith_carry_bit(pi) ++struct pic2_info *pi; ++{ ++ pic2_write_bits(pi, 1, 1); ++ ++ if (pi->bs.bits == 0) { ++ pi->bs.zero = 0; ++ } else { ++ while (--pi->bs.bits) ++ pic2_write_bits(pi, 0, 1); ++ pi->bs.zero = 1; ++ } ++} ++ ++static void pic2_arith_encode_bit(pi, n, c) ++struct pic2_info *pi; ++int n, c; ++{ ++ int pp; ++ long *c_sum, *c_0_sum; ++ ++ c_sum = (long *) pi->mulu_tab; ++ c_0_sum = c_sum + PIC2_ARITH_CONTEXT + 1; ++ ++ if (pi->dd == 0) { ++ c_sum[c]++; ++ if (n == 0) ++ c_0_sum[c]++; ++ return; ++ } ++ pp = pi->mulu_tab[(pi->aa & 0x7f00) / 2 + c]; ++ if (n != 0) { ++ pi->cc = pi->cc + pp; ++ if (pi->cc > 0xffff) { ++ pic2_arith_carry_bit(pi); ++ pi->cc = pi->cc & 0xffff; ++ } ++ pi->aa = pi->aa - pp; ++ while (pi->aa < 0x8000) { ++ if (pi->cc & 0x8000) ++ pic2_arith_write_one_bit(pi); ++ else ++ pic2_arith_write_zero_bit(pi); ++ pi->cc = (pi->cc * 2) & 0xffff; ++ pi->aa = pi->aa * 2; ++ } ++ } else { ++ pi->aa = pp; ++ ++ while (pi->aa < 0x8000) { ++ if (pi->cc & 0x8000) ++ pic2_arith_write_one_bit(pi); ++ else ++ pic2_arith_write_zero_bit(pi); ++ pi->cc = (pi->cc * 2) & 0xffff; ++ pi->aa = pi->aa * 2; ++ } ++ } ++} ++ ++static void pic2_arith_encode_nbyte(pi, n, c, max) ++struct pic2_info *pi; ++int n, c, max; ++{ ++ short i; ++ ++ for (i = 0; i < n; i++) { ++ pic2_arith_encode_bit(pi, 0, c + i); ++ } ++ if (n < max) ++ pic2_arith_encode_bit(pi, 1, c + n); ++} ++ ++static void pic2_arith_encode_nn(pi, n, c) ++struct pic2_info *pi; ++int n, c; ++{ ++ if (n < 1) { ++ pic2_arith_encode_bit(pi, 1, c); ++ } else if (n < 1 + 2) { ++ pic2_arith_encode_bit(pi, 0, c); ++ pic2_arith_encode_bit(pi, 1, c + 1); ++ n -= 1; ++ pic2_arith_encode_bit(pi, n & 1, c + 8); ++ } else if (n < 1 + 2 + 4) { ++ pic2_arith_encode_bit(pi, 0, c); ++ pic2_arith_encode_bit(pi, 0, c + 1); ++ pic2_arith_encode_bit(pi, 1, c + 2); ++ n -= 1 + 2; ++ pic2_arith_encode_bit(pi, n & 1, c + 8); ++ pic2_arith_encode_bit(pi, n & 2, c + 9); ++ } else if (n < 1 + 2 + 4 + 8) { ++ pic2_arith_encode_bit(pi, 0, c); ++ pic2_arith_encode_bit(pi, 0, c + 1); ++ pic2_arith_encode_bit(pi, 0, c + 2); ++ pic2_arith_encode_bit(pi, 1, c + 3); ++ n -= 1 + 2 + 4; ++ pic2_arith_encode_bit(pi, n & 1, c + 8); ++ pic2_arith_encode_bit(pi, n & 2, c + 9); ++ pic2_arith_encode_bit(pi, n & 4, c + 10); ++ } else if (n < 1 + 2 + 4 + 8 + 16) { ++ pic2_arith_encode_bit(pi, 0, c); ++ pic2_arith_encode_bit(pi, 0, c + 1); ++ pic2_arith_encode_bit(pi, 0, c + 2); ++ pic2_arith_encode_bit(pi, 0, c + 3); ++ pic2_arith_encode_bit(pi, 1, c + 4); ++ n -= 1 + 2 + 4 + 8; ++ pic2_arith_encode_bit(pi, n & 1, c + 8); ++ pic2_arith_encode_bit(pi, n & 2, c + 9); ++ pic2_arith_encode_bit(pi, n & 4, c + 10); ++ pic2_arith_encode_bit(pi, n & 8, c + 11); ++ } else if (n < 1 + 2 + 4 + 8 + 16 + 32) { ++ pic2_arith_encode_bit(pi, 0, c); ++ pic2_arith_encode_bit(pi, 0, c + 1); ++ pic2_arith_encode_bit(pi, 0, c + 2); ++ pic2_arith_encode_bit(pi, 0, c + 3); ++ pic2_arith_encode_bit(pi, 0, c + 4); ++ pic2_arith_encode_bit(pi, 1, c + 5); ++ n -= 1 + 2 + 4 + 8 + 16; ++ pic2_arith_encode_bit(pi, n & 1, c + 8); ++ pic2_arith_encode_bit(pi, n & 2, c + 9); ++ pic2_arith_encode_bit(pi, n & 4, c + 10); ++ pic2_arith_encode_bit(pi, n & 8, c + 11); ++ pic2_arith_encode_bit(pi, n & 16, c + 12); ++ } else if (n < 1 + 2 + 4 + 8 + 16 + 32 + 64) { ++ pic2_arith_encode_bit(pi, 0, c); ++ pic2_arith_encode_bit(pi, 0, c + 1); ++ pic2_arith_encode_bit(pi, 0, c + 2); ++ pic2_arith_encode_bit(pi, 0, c + 3); ++ pic2_arith_encode_bit(pi, 0, c + 4); ++ pic2_arith_encode_bit(pi, 0, c + 5); ++ pic2_arith_encode_bit(pi, 1, c + 6); ++ n -= 1 + 2 + 4 + 8 + 16 + 32; ++ pic2_arith_encode_bit(pi, n & 1, c + 8); ++ pic2_arith_encode_bit(pi, n & 2, c + 9); ++ pic2_arith_encode_bit(pi, n & 4, c + 10); ++ pic2_arith_encode_bit(pi, n & 8, c + 11); ++ pic2_arith_encode_bit(pi, n & 16, c + 12); ++ pic2_arith_encode_bit(pi, n & 32, c + 13); ++ } else if (n < 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128) { ++ pic2_arith_encode_bit(pi, 0, c); ++ pic2_arith_encode_bit(pi, 0, c + 1); ++ pic2_arith_encode_bit(pi, 0, c + 2); ++ pic2_arith_encode_bit(pi, 0, c + 3); ++ pic2_arith_encode_bit(pi, 0, c + 4); ++ pic2_arith_encode_bit(pi, 0, c + 5); ++ pic2_arith_encode_bit(pi, 0, c + 6); ++ pic2_arith_encode_bit(pi, 1, c + 7); ++ n -= 1 + 2 + 4 + 8 + 16 + 32 + 64; ++ pic2_arith_encode_bit(pi, n & 1, c + 8); ++ pic2_arith_encode_bit(pi, n & 2, c + 9); ++ pic2_arith_encode_bit(pi, n & 4, c + 10); ++ pic2_arith_encode_bit(pi, n & 8, c + 11); ++ pic2_arith_encode_bit(pi, n & 16, c + 12); ++ pic2_arith_encode_bit(pi, n & 32, c + 13); ++ pic2_arith_encode_bit(pi, n & 64, c + 14); ++ } else { ++ pic2_arith_encode_bit(pi, 0, c); ++ pic2_arith_encode_bit(pi, 0, c + 1); ++ pic2_arith_encode_bit(pi, 0, c + 2); ++ pic2_arith_encode_bit(pi, 0, c + 3); ++ pic2_arith_encode_bit(pi, 0, c + 4); ++ pic2_arith_encode_bit(pi, 0, c + 5); ++ pic2_arith_encode_bit(pi, 0, c + 6); ++ pic2_arith_encode_bit(pi, 0, c + 7); ++ } ++} ++ ++static void pic2_arith_press_chain(pi, x) ++struct pic2_info *pi; ++int x; ++{ ++ int b, d; ++ pixel c; ++ ++ b = -(pi->flag_now[x]); ++ c = pi->vram_now[x]; ++ d = 0; ++ ++ if (b < 0) ++ b = 0; ++ ++ if (pi->flag_next[x] == 1 && pi->vram_next[x] == c) { ++ d = 1; ++ pi->flag_next[x] = -1; ++ } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == c) { ++ d = 2; ++ pi->flag_next[x - 1] = -2; ++ } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == c) { ++ d = 3; ++ pi->flag_next[x + 1] = -3; ++ } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == c) { ++ d = 4; ++ pi->flag_next[x - 2] = -4; ++ } else if (pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == c) { ++ if ((pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == c) ++ || (pi->flag_now[x + 1] != 0 && pi->vram_now[x + 1] == c) ++ || (pi->flag_now[x + 3] != 0 && pi->vram_now[x + 3] == c)) { ++ pic2_arith_encode_nbyte(pi, 0, 80 + 6 * b, 5); ++ return; ++ } ++ d = 5; ++ pi->flag_next[x + 2] = -5; ++ } ++ pic2_arith_encode_nbyte(pi, d, 80 + 6 * b, 5); ++} ++ ++static void pic2_arith_put_number(pi, xn, xa, xb) ++struct pic2_info *pi; ++int xn, xa, xb; ++{ ++ short n; ++ byte maxcol; ++ ++ maxcol = 0xff >> (8 - pi->header->depth / 3); ++ ++ if (xa > ((int) maxcol >> 1)) { ++ if (xb > xa) ++ n = (xb - xa) * 2 - 1; ++ else if (xa - ((int) maxcol - xa) > xb) ++ n = maxcol - xb; ++ else ++ n = (xa - xb) * 2; ++ } else { ++ if (xb <= xa) ++ n = (xa - xb) * 2; ++ else if (2 * xa < xb) ++ n = xb; ++ else ++ n = (xb - xa) * 2 - 1; ++ } ++ pic2_arith_encode_nn(pi, n, xn); ++} ++ ++static void pic2_arith_write_color(pi, x) ++struct pic2_info *pi; ++int x; ++{ ++ pixel c1, c2, cc; ++ short g0, r0, b0, r, g, b; ++ int i, j; ++ unsigned short k; ++ pixel *p, *pp; ++ short colbits; ++ pixel rmask, gmask, bmask; ++ byte maxcol; ++ ++ colbits = pi->header->depth / 3; ++ rmask = (0xff >> (8 - colbits)) << (colbits * 2); ++ gmask = (0xff >> (8 - colbits)) << colbits; ++ bmask = (0xff >> (8 - colbits)); ++ maxcol = (byte) bmask; ++ ++ cc = pi->vram_now[x]; ++ c1 = pi->vram_prev[x]; ++ k = ((c1 >> ((colbits - 3) * 3)) & 0x1c0) ++ | ((c1 >> ((colbits - 3) * 2)) & 0x038) ++ | ((c1 >> (colbits - 3) ) & 0x007); ++ if (colbits == 5) ++ k = pic2_exchange_rg(k, 3); ++ ++ p = pi->cache[k]; ++ for (i = 0; i < (PIC2_ARITH_CACHE - 1); i++) { ++ if (cc == *p++) ++ break; ++ } ++ if (i == (PIC2_ARITH_CACHE - 1)) { ++ pp = p - 1; ++ for (j = i; j > 0; j--) { ++ *--p = *--pp; ++ } ++ pi->cache[k][0] = cc; ++ pic2_arith_encode_bit(pi, 1, pi->cache_hit_c); ++ pi->cache_hit_c = 16; ++ ++ c2 = pi->vram_now[x - 1]; ++ r = ((c1 & rmask) + (c2 & rmask)) >> (colbits * 2 + 1); ++ g = ((c1 & gmask) + (c2 & gmask)) >> (colbits + 1); ++ b = ((c1 & bmask) + (c2 & bmask)) >> ( 1); ++ ++ r0 = (cc >> (colbits * 2)) & maxcol; ++ g0 = (cc >> colbits ) & maxcol; ++ b0 = cc & maxcol; ++ ++ r = r + g0 - g; ++ if (r < 0) ++ r = 0; ++ else if (r > (short) maxcol) ++ r = maxcol; ++ ++ b = b + g0 - g; ++ if (b < 0) ++ b = 0; ++ else if (b > (short) maxcol) ++ b = maxcol; ++ ++ pic2_arith_put_number(pi, 32, g, g0); ++ pic2_arith_put_number(pi, 48, r, r0); ++ pic2_arith_put_number(pi, 64, b, b0); ++ } else { ++ *--p = pi->cache[k][i / 2]; ++ pi->cache[k][i / 2] = pi->cache[k][0]; ++ pi->cache[k][0] = cc; ++ ++ pic2_arith_encode_bit(pi, 0, pi->cache_hit_c); ++ pi->cache_hit_c = 15; ++ pic2_arith_encode_nn(pi, i, 17); ++ } ++} ++ ++static void pic2_arith_press_line2(pi) ++struct pic2_info *pi; ++{ ++ int x, xw, ymax; ++ pixel cc; ++ ++ xw = pi->block->x_wid; ++ ymax = pi->block->y_wid -1; ++ cc = pi->vram_now[xw - 1]; /* last color */ ++ pi->vram_next[-1] = cc; ++ ++ /* mark change point */ ++ for (x = 0; x < xw; x++) ++ if (cc != pi->vram_next[x]) { ++ pi->flag_next[x] = 1; ++ cc = pi->vram_next[x]; ++ } else ++ pi->flag_next[x] = 0; ++ ++ for (x = 0; x < xw; x++) { ++ if (pi->flag_now[x] == 1) { /* change point */ ++ pi->flag2_now [x + 1]++; ++ pi->flag2_now [x + 2]++; ++ pi->flag2_next [x - 1]++; ++ pi->flag2_next [x ]++; ++ pi->flag2_next [x + 1]++; ++ pi->flag2_next2[x - 1]++; ++ pi->flag2_next2[x ]++; ++ pi->flag2_next2[x + 1]++; ++ ++ /* write change point */ ++ pic2_arith_encode_bit(pi, 1, pi->flag2_now[x]); ++ ++ /* write color */ ++ pic2_arith_write_color(pi, x); ++ ++ /* if not last line, write chain */ ++ if (pi->ynow - 1 < ymax) ++ pic2_arith_press_chain(pi, x); ++ } else if (pi->flag_now[x] == 0) /* not on chain */ ++ /* write change point */ ++ pic2_arith_encode_bit(pi, 0, pi->flag2_now[x]); ++ else /* on chain */ ++ /* if not on last line, write next chain */ ++ if (pi->ynow - 1 < ymax) ++ pic2_arith_press_chain(pi, x); ++ } ++} ++ ++static int pic2_arith_press_line(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ int i, xw, ymax; ++ long *c_sum, *c_0_sum; ++ ++ xw = pi->block->x_wid; ++ ymax = pi->block->y_wid -1; ++ c_sum = (long *) pi->mulu_tab; ++ c_0_sum = c_sum + PIC2_ARITH_CONTEXT +1; ++ ++ pic2_handle_para(pi, 0); ++ ++ xvbzero((char *) pi->flag2_next2 - 4, ++ (8 + xw) * sizeof(pi->flag2_next2[0])); ++ ++ if (pi->ynow == 0) { /* first line */ ++ int x; ++ pixel cc = 0; ++ ++ if (pi->dd != 0) { /* compress pass */ ++ unsigned short c_tab[PIC2_ARITH_CONTEXT]; ++ ++ for (i = 0; i < PIC2_ARITH_CONTEXT; i++) { ++ unsigned long a, b; ++ a = c_0_sum[i]; ++ b = c_sum[i]; ++ while (a > 32767) { ++ a /= 2; ++ b /= 2; ++ } ++ if (a == b) ++ c_tab[i] = 0xffff; /* b==0 here, too */ ++ else ++ c_tab[i] = (65536 * a) / b; /* a < b, so less 65536 */ ++ } ++ for (i = 0; i < 16384; i++) { ++ pi->mulu_tab[i] = (long) (i / 128 + 128) * (int) c_tab[i & 127] / 256; ++ if (pi->mulu_tab[i] == 0) ++ pi->mulu_tab[i] = 1; /* 0 is wrong */ ++ } ++ for (i = 0; i < PIC2_ARITH_CONTEXT; i++) ++ pic2_write_short(pi, c_tab[i]); ++ ++ xvbzero((char *) pi->vram_now, xw * sizeof(pi->vram_now[0])); ++ } else { /* statistical pass */ ++ xvbzero((char *) c_0_sum, PIC2_ARITH_CONTEXT * sizeof(c_0_sum[0])); ++ xvbzero((char *) c_sum, PIC2_ARITH_CONTEXT * sizeof(c_sum[0])); ++ } ++ ++ /* initialize flags */ ++ xvbzero((char *) pi->cache, 8 * 8 * 8 * sizeof(pi->cache[0])); ++ xvbzero((char *) pi->cache_pos, 8 * 8 * 8 * sizeof(pi->cache_pos[0])); ++ ++ xvbzero((char *) pi->flag2_next - 4, ++ (8 + xw) * sizeof(pi->flag2_next[0])); ++ xvbzero((char *) pi->flag2_next2 - 4, ++ (8 + xw) * sizeof(pi->flag2_next2[0])); ++ ++ pi->vram_next[-1] = cc; ++ for (x = 0; x < xw; x++) ++ if (cc != pi->vram_next[x]) { ++ pi->flag_next[x] = 1; ++ cc = pi->vram_next[x]; ++ } else ++ pi->flag_next[x] = 0; ++ ++ pi->aa = 0xffff; ++ cc = 0; ++ pi->cache_hit_c = 16; ++ } else /* after second line */ ++ pic2_arith_press_line2(pi); ++ ++ if (pi->ynow == ymax) { ++ pi->ynow++; ++ pic2_handle_para(pi, 1); ++ pic2_handle_para(pi, 0); ++ pic2_arith_press_line2(pi); ++ } ++ /* line buffer for next data */ ++ if (line != NULL) ++ *line = pi->vram_prev; ++ ++ pi->ynow++; ++ ++ if (pi->ynow - 1 < ymax) { ++ pic2_handle_para(pi, 1); ++ return (pi->ynow); ++ } else { /* end */ ++ if (pi->dd == 0) { /* statistical pass */ ++ pi->dd = 1; ++ pi->ynow = 0; ++ pic2_handle_para(pi, 1); ++ return (0); ++ } else { ++ pic2_handle_para(pi, 1); ++ pic2_arith_flush_bit_buf(pi); ++ return (-2); /* end */ ++ } ++ } ++} ++ ++static int pic2_arith_saver_init(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ pi->ynow = 0; ++ ++ /* check the color depth */ ++ if (pi->header->depth % 3) ++ pic2_error(pi, PIC2_DEPTH); ++ ++ /* set next line function */ ++ pi->next_line = pic2_arith_press_line; ++ ++ if (line != NULL) ++ *line = pi->vram_next + 4; ++ ++ pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET); ++ ++ /* clear bit field marker */ ++ pi->bs.rest = 0; ++ pi->bs.cur = 0; ++ pi->bs.zero = 0; ++ pi->bs.bits = 0; ++ ++ return (0); ++} ++ ++/* ++ * These functions are fast pic2 format compressor. ++ */ ++static void pic2_fast_write_length(pi, n) ++struct pic2_info *pi; ++int n; ++{ ++ int a, b; ++ static const unsigned short len_data[8][2] = { ++ {1, 0}, ++ {1, 0}, ++ {3, 4}, ++ {3, 5}, ++ {5, 24}, ++ {5, 25}, ++ {5, 26}, ++ {5, 27}, ++ }; ++ ++ n++; ++ if (n < 8) ++ pic2_write_bits(pi, len_data[n][1], len_data[n][0]); ++ else { ++ a = 0; ++ b = 2; ++ while (n > b - 1) { ++ a = a + 1; ++ b = b * 2; ++ } ++ pic2_write_bits(pi, 0xfffffffe, a + 1); ++ if (a > 0) ++ pic2_write_bits(pi, n - b / 2, a); ++ } ++} ++ ++static void pic2_fast_press_chain(pi, x) ++struct pic2_info *pi; ++int x; ++{ ++ int ymax; ++ pixel cc; ++ ++ ymax = pi->block->y_wid -1; ++ cc = pi->vram_now[x]; ++ ++ if (pi->ynow - 1 == ymax) { ++ pic2_write_bits(pi, 0, 1); ++ return; ++ } ++ if (pi->flag_next[x] == 1 && pi->vram_next[x] == cc) { ++ pi->flag_next[x] = -1; ++ pic2_write_bits(pi, 3, 2); ++ } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == cc) { ++ pi->flag_next[x - 1] = -1; ++ pic2_write_bits(pi, 11, 4); ++ } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == cc) { ++ pi->flag_next[x + 1] = -1; ++ pic2_write_bits(pi, 9, 4); ++ } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == cc) { ++ pi->flag_next[x - 2] = -1; ++ pic2_write_bits(pi, 10, 4); ++ } else if ((pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == cc) ++ && !(pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == cc)) { ++ pi->flag_next[x + 2] = -1; ++ pic2_write_bits(pi, 8, 4); ++ } else ++ pic2_write_bits(pi, 0, 1); ++} ++ ++static void pic2_fast_press_chain2(pi, x) ++struct pic2_info *pi; ++int x; ++{ ++ int ymax; ++ pixel cc; ++ char *chain_buff; ++ ++ ymax = pi->block->y_wid -1; ++ chain_buff = (char *) pi->mulu_tab; ++ cc = pi->vram_now[x]; ++ ++ if (pi->ynow - 1 == ymax) { ++ chain_buff[pi->cc++] = 0; ++ return; ++ } ++ if (pi->flag_next[x] == 1 && pi->vram_next[x] == cc) { ++ pi->flag_next[x] = -1; ++ chain_buff[pi->cc++] = 1; ++ } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == cc) { ++ pi->flag_next[x - 1] = -1; ++ chain_buff[pi->cc++] = 2; ++ } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == cc) { ++ pi->flag_next[x + 1] = -1; ++ chain_buff[pi->cc++] = 3; ++ } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == cc) { ++ pi->flag_next[x - 2] = -1; ++ chain_buff[pi->cc++] = 4; ++ } else if ((pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == cc) ++ && !(pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == cc)) { ++ pi->flag_next[x + 2] = -1; ++ chain_buff[pi->cc++] = 5; ++ } else ++ chain_buff[pi->cc++] = 0; ++} ++ ++static void pic2_fast_flush_chain(pi) ++struct pic2_info *pi; ++{ ++ int i; ++ char *chain_buf; ++ ++ chain_buf = (char *) pi->mulu_tab; ++ for (i = 0; i < pi->cc; i++){ ++ switch (chain_buf[i]) { ++ case 0: ++ pic2_write_bits(pi, 0, 1); ++ break; ++ case 1: ++ pic2_write_bits(pi, 3, 2); ++ break; ++ case 2: ++ pic2_write_bits(pi, 11, 4); ++ break; ++ case 3: ++ pic2_write_bits(pi, 9, 4); ++ break; ++ case 4: ++ pic2_write_bits(pi, 10, 4); ++ break; ++ case 5: ++ pic2_write_bits(pi, 8, 4); ++ break; ++ } ++ } ++ pi->cc = 0; ++} ++ ++static void pic2_fast_write_color(pi, x) ++struct pic2_info *pi; ++int x; ++{ ++ pixel cc, bc; ++ unsigned short j, k, m; ++ short depth, colbits; ++ pixel (*cache)[PIC2_FAST_CACHE]; ++ ++ depth = pi->header->depth; ++ colbits = depth / 3; ++ cache = (pixel (*)[PIC2_FAST_CACHE]) pi->cache; ++ ++ bc = pi->vram_now[x - 1]; ++ bc = pic2_exchange_rg(bc, colbits); ++ k = pic2_shift_bits(bc, 8 - depth); ++ cc = pi->vram_now[x]; ++ m = pi->cache_pos[k]; ++ ++ for (j = 0; j < PIC2_FAST_CACHE; j++) ++ if (cache[k][(m + j) & (PIC2_FAST_CACHE - 1)] == cc) ++ break; ++ ++ if (j == PIC2_FAST_CACHE) { ++ m = (m - 1) & (PIC2_FAST_CACHE - 1); ++ pi->cache_pos[k] = m; ++ cache[k][m] = cc; ++ ++ cc = pic2_exchange_rg(cc, colbits); ++ pic2_write_bits(pi, 0, 1); ++ pic2_write_bits(pi, cc, depth); ++ } else { ++ pic2_write_bits(pi, 1, 1); ++ pic2_write_bits(pi, j, 6); ++ } ++} ++ ++static void pic2_fast_press_line2(pi) ++struct pic2_info *pi; ++{ ++ int x, xw; ++ pixel cc; ++ ++ xw = pi->block->x_wid; ++ cc = pi->vram_now[xw - 1]; /* last color */ ++ pi->vram_next[-1] = cc; ++ ++ /* mark change point */ ++ for (x = 0; x < xw; x++) ++ if (cc != pi->vram_next[x]) { ++ pi->flag_next[x] = 1; ++ cc = pi->vram_next[x]; ++ } else ++ pi->flag_next[x] = 0; ++ ++ for (x = 0; x < xw; x++) ++ if (pi->flag_now[x] == 1) { /* change point */ ++ if (pi->aa >= 1023) ++ pi->aa++; ++ pic2_fast_write_length(pi, pi->aa); ++ pic2_fast_flush_chain(pi); ++ pi->aa = 0; ++ pic2_fast_write_color(pi, x); ++ pic2_fast_press_chain(pi, x); ++ } else if (pi->flag_now[x] == 0) { ++ pi->aa++; ++ } else { ++ pic2_fast_press_chain2(pi, x); ++ if (pi->cc == 1023) { ++ pic2_fast_write_length(pi, 1023); ++ pic2_fast_flush_chain(pi); ++ pi->aa = 0; ++ } ++ } ++} ++ ++static int pic2_fast_press_line(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ int xw, ymax; ++ ++ xw = pi->block->x_wid; ++ ymax = pi->block->y_wid -1; ++ ++ pic2_handle_para(pi, 0); ++ ++ if (pi->ynow == 0) { /* first line */ ++ int x; ++ pixel cc = 0; ++ ++ /* initialize flags */ ++ xvbzero((char *) pi->cache, 256 * sizeof(pi->cache[0])); ++ xvbzero((char *) pi->cache_pos, ++ PIC2_FAST_CACHE * sizeof(pi->cache_pos[0])); ++ ++ /* mark change point */ ++ pi->vram_next[-1] = cc; ++ for (x = 0; x < xw; x++) ++ if (cc != pi->vram_next[x]) { ++ pi->flag_next[x] = 1; ++ cc = pi->vram_next[x]; ++ } else ++ pi->flag_next[x] = 0; ++ ++ pi->cc = 0; ++ pi->aa = 0; ++ } else /* after second line */ ++ pic2_fast_press_line2(pi); ++ ++ if (pi->ynow == ymax) { ++ pi->ynow++; ++ pic2_handle_para(pi, 1); ++ pic2_handle_para(pi, 0); ++ pic2_fast_press_line2(pi); ++ } ++ /* line buffer for next data */ ++ if (line != NULL) ++ *line = pi->vram_prev; ++ ++ pi->ynow++; ++ ++ if (pi->ynow - 1 < ymax) { ++ pic2_handle_para(pi, 1); ++ return (pi->ynow); ++ } else { /* end */ ++ pic2_handle_para(pi, 1); ++ if (pi->aa >= 1023) ++ pi->aa++; ++ pic2_fast_write_length(pi, pi->aa); ++ pic2_fast_flush_chain(pi); ++ return (-2); /* end */ ++ } ++} ++ ++static int pic2_fast_saver_init(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ pi->ynow = 0; ++ ++ /* check the color depth */ ++ if (pi->header->depth % 3) ++ pic2_error(pi, PIC2_DEPTH); ++ ++ /* set next line function */ ++ pi->next_line = pic2_fast_press_line; ++ if (line != NULL) ++ *line = pi->vram_next + 4; ++ ++ pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET); ++ ++ /* clear bit field marker */ ++ pi->bs.rest = 0; ++ pi->bs.cur = 0; ++ ++ return (0); ++} ++ ++/* ++ * These functions are beta pic2 format compressor. ++ */ ++static int pic2_beta_press_line(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ int i, xw, ymax; ++ byte *p; ++ pixel *pc; ++ short depth, pixbyte, colbits; ++ ++ depth = pi->header->depth; ++ pixbyte = depth / 8 + ((depth % 8) > 0); ++ colbits = depth / 3; ++ ++ xw = pi->block->x_wid; ++ ymax = pi->block->y_wid - 1; ++ ++ pc = pi->vram_now; ++ p = (byte *) pi->vram_prev; ++ if (pixbyte == 3) { ++ for (i = 0; i < xw; i++, pc++) { ++ *p++ = *pc >> 16; ++ *p++ = *pc >> 8; ++ *p++ = *pc; ++ } ++ pic2_write_file(pi, pi->vram_prev, (size_t) (xw * 3)); ++ } else if (pixbyte == 2) { ++ if (strncmp(pi->block->id, "P2BM", 4) == 0) ++ for (i = 0; i < xw; i++, pc++) { ++ if (colbits == 5) { ++ *pc = pic2_exchange_rg(*pc, colbits); ++ *pc <<= 1; ++ } ++ *p++ = *pc >> 8; ++ *p++ = *pc; ++ } ++ else ++ for (i = 0; i < xw; i++, pc++) { ++ if (colbits == 5) { ++ *pc = pic2_exchange_rg(*pc, colbits); ++ *pc <<= 1; ++ } ++ *p++ = *pc; ++ *p++ = *pc >> 8; ++ } ++ pic2_write_file(pi, pi->vram_prev, (size_t) (xw * 2)); ++ } else { ++ for (i = 0; i < xw; i++, pc++) ++ *p++ = *pc; ++ pic2_write_file(pi, pi->vram_prev, (size_t) xw); ++ } ++ if (line != NULL) ++ *line = pi->vram_now; ++ ++ pi->ynow++; ++ if (pi->ynow > ymax) ++ return (-2); ++ return (pi->ynow); ++} ++ ++static int pic2_beta_saver_init(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ pi->ynow = 0; ++ ++ *line = pi->vram_now; ++ pi->next_line = pic2_beta_press_line; ++ pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET); ++ return (0); ++} ++ ++/* ++ * This function saves compressed data. ++ */ ++static void pic2_write_data(pi, data, ptype, x_offset, y_offset, w, h, ++ rmap, gmap, bmap, type, depth) ++struct pic2_info *pi; ++byte *data; ++int ptype; ++int x_offset, y_offset; ++int w, h; ++byte *rmap, *gmap, *bmap; ++int type, depth; ++{ ++ int i, line; ++ pixel *linep; ++ short colbits; ++ ++ colbits = pi->header->depth / 3; ++ ++ line = pic2_save_block(pi, &linep, x_offset, y_offset, w, h, ++ form_tab[type].id, 0xffffffff); ++ while (line >= 0) { ++ byte r, g, b; ++ int pic_idx; ++ ++ pic_idx = line * w * ((ptype == PIC24) ? 3 : 1); ++ ++ for (i = 0; i < w; i++) { ++ if (ptype != PIC24) { ++ r = rmap[data[pic_idx]]; ++ g = gmap[data[pic_idx]]; ++ b = bmap[data[pic_idx]]; ++ pic_idx++; ++ } else { ++ r = data[pic_idx++]; ++ g = data[pic_idx++]; ++ b = data[pic_idx++]; ++ } ++ if (pi->writing_grey) ++ r = g = b = MONO(r, g, b); ++ ++ r = pic2_convert_color_bits(r, 8, colbits); ++ g = pic2_convert_color_bits(g, 8, colbits); ++ b = pic2_convert_color_bits(b, 8, colbits); ++ ++ linep[i] = ((pixel) r << (colbits * 2)) ++ | ((pixel) g << colbits ) ++ | ((pixel) b ); ++ } ++ line = pic2_next_line(pi, &linep); ++ WaitCursor(); ++ } ++} ++ ++/* ++ * This function compresses/extracts one line buffer. ++ */ ++static int pic2_next_line(pi, line) ++struct pic2_info *pi; ++pixel **line; ++{ ++ int res; ++ ++ res = pi->next_line(pi, line); ++ if (res == -2) { ++ if (pi->mode == PIC2_WRITE_MODE) { ++ long new_pos; ++ ++ new_pos = pic2_tell_file(pi); ++ pi->block->size = new_pos - pi->next_pos; ++ pic2_seek_file(pi, pi->next_pos, SEEK_SET); ++ pic2_write_block_header(pi); ++ pi->next_pos = new_pos; ++ if (DEBUG) ++ pic2_show_pic2_info(pi); ++ } ++ pic2_free_buffer(pi); ++ } ++ return (res); ++} ++ ++/* ++ * These functions find the pic2 image block. ++ * pic2_next_block: ++ * moves the file pointer to the next image block. ++ * pic2_find_block: ++ * finds the first image block and moves the file pointer there. ++ */ ++static int pic2_next_block(pi) ++struct pic2_info *pi; ++{ ++ int i; ++ ++ if (pi->mode != PIC2_READ_MODE) ++ return (-1); ++ ++ /* go to block for read */ ++ pic2_seek_file(pi, pi->next_pos, SEEK_SET); ++ ++ /* read the head of block header */ ++ pic2_read_block_header1(pi); ++ ++ /* end block ? */ ++ if (pi->block->id[0] == 0) ++ return (0); ++ ++ /* set current block */ ++ pi->block_pos = pi->next_pos; ++ ++ /* set next block */ ++ pi->next_pos += pi->block->size; ++ ++ /* check block id */ ++ for (i = 0; i < n_form_tab; i++) { ++ if (xvbcmp(pi->block->id, form_tab[i].id, (size_t) 4) == 0) ++ break; ++ } ++ if (i == n_form_tab) ++ return (2); ++ ++ /* read the rest of block header */ ++ pic2_read_block_header2(pi); ++ ++ if (pi->block->x_offset + pi->block->x_wid > pi->x_max) ++ pi->x_max = pi->block->x_offset + pi->block->x_wid; ++ ++ if (pi->block->y_offset + pi->block->y_wid > pi->y_max) ++ pi->y_max = pi->block->y_offset + pi->block->y_wid; ++ ++ if (DEBUG) ++ pic2_show_pic2_info(pi); ++ return (1); ++} ++ ++static int pic2_find_block(pi) ++struct pic2_info *pi; ++{ ++ if (pi->mode != PIC2_READ_MODE) ++ return (-1); ++ ++ pi->next_pos = pi->header->size; ++ return (pic2_next_block(pi)); ++} ++ ++/* ++ * These functions load/save the pic2 image block. ++ * pic2_load_block: ++ * initializes loader information with current block information. ++ * pic2_save_block: ++ * initializes saver information. ++ */ ++static int pic2_load_block(pi) ++struct pic2_info *pi; ++{ ++ int i; ++ ++ for (i = 0; i < n_form_tab; i++) { ++ if (xvbcmp(pi->block->id, form_tab[i].id, (size_t) 4) == 0) ++ break; ++ } ++ if (i == n_form_tab) ++ return (2); ++ ++ pic2_alloc_buffer(pi); ++ return (form_tab[i].loader_init(pi)); ++} ++ ++static int pic2_save_block(pi, line, x, y, xw, yw, id, opaque) ++struct pic2_info *pi; ++pixel **line; ++int x, y, xw, yw; ++char *id; ++pixel opaque; ++{ ++ int i; ++ ++ for (i = 0; i < n_form_tab; i++) { ++ if (xvbcmp(id, form_tab[i].id, (size_t) 4) == 0) ++ break; ++ } ++ if (i == n_form_tab) ++ return (2); ++ ++ strncpy(pi->block->id, id, 4); ++ pi->block->x_wid = xw; ++ pi->block->y_wid = yw; ++ pi->block->x_offset = x; ++ pi->block->y_offset = y; ++ pi->block->reserve = 0; ++ ++ if (x < 0) ++ x = 0; ++ if (y < 0) ++ y = 0; ++ if (x + xw > pi->x_max) ++ pi->x_max = x + xw; ++ if (y + yw > pi->y_max) ++ pi->y_max = y + yw; ++ ++ if (opaque != 0xffffffff) { ++ pi->block->flag = 1; ++ pi->block->opaque = opaque; ++ } else { ++ pi->block->flag = 0; ++ pi->block->opaque = 0; ++ } ++ pic2_alloc_buffer(pi); ++ ++ return (form_tab[i].saver_init(pi, line)); ++} ++ ++/* ++ * These functions set/get palettes. ++ * pic2_read_palette: ++ * copy the palettes from pic2_info to PICINFO. ++ * pic2_write_palette: ++ * copy the palettes from PICINFO to pic2_info. ++ */ ++#ifndef PIC2_IGNORE_UNUSED_FUNCTIONS ++static void pic2_read_palette(pi, r, g, b) ++struct pic2_info *pi; ++byte *r, *g, *b; ++{ ++ int i; ++ ++ if (pi->n_pal > 256) ++ pi->n_pal = 256; ++ ++ if (pi->pal_bits > 8) ++ pi->pal_bits = 8; ++ ++ for (i = 0; i < pi->n_pal; i++) { ++ *r++ =pic2_convert_color_bits(pi->pal[i][0] >> (8 - pi->pal_bits), ++ pi->pal_bits, 8); ++ *g++ =pic2_convert_color_bits(pi->pal[i][1] >> (8 - pi->pal_bits), ++ pi->pal_bits, 8); ++ *b++ =pic2_convert_color_bits(pi->pal[i][2] >> (8 - pi->pal_bits), ++ pi->pal_bits, 8); ++ } ++} ++ ++static void pic2_write_palette(pi, n_pal, pal_bits, r, g, b) ++struct pic2_info *pi; ++int n_pal, pal_bits; ++byte *r, *g, *b; ++{ ++ int i; ++ ++ if (n_pal > 256) ++ pi->n_pal = 256; ++ else ++ pi->n_pal = n_pal; ++ ++ if (pal_bits > 8) ++ pi->pal_bits = 8; ++ else ++ pi->pal_bits = pal_bits; ++ ++ for (i = 0; i < n_pal; i++) { ++ pi->pal[i][0] = pic2_convert_color_bits(*r++, 8, pal_bits) ++ << (8 - pal_bits); ++ pi->pal[i][1] = pic2_convert_color_bits(*g++, 8, pal_bits) ++ << (8 - pal_bits); ++ pi->pal[i][2] = pic2_convert_color_bits(*b++, 8, pal_bits) ++ << (8 - pal_bits); ++ } ++} ++#endif /* PIC2_IGNORE_UNUSED_FUNCTIONS */ ++ ++/* ++ * These functions handle color bits. ++ * pic2_convert_color_bits: ++ * converts color bits. ++ * pic2_pad_color_bits: ++ * pads color bits. ++ * pic2_reduce_color_bits: ++ * reduces color bits. ++ * pic2_exchange_rg: ++ * exchanges red and green values. ++ */ ++static byte pic2_convert_color_bits(c, from, to) ++int c, from, to; ++{ ++ if (from == to) ++ return ((byte) c); ++ else if (from < to) ++ return (pic2_pad_color_bits(c, from, to)); ++ else ++ return (pic2_reduce_color_bits(c, from, to)); ++} ++ ++static byte pic2_pad_color_bits(c, from, to) ++int c, from, to; ++{ ++ byte p = 0; ++ ++ do { ++ to -= from; ++ p |= pic2_shift_bits(c, to); ++ } while (to >= 0); ++ return (p); ++} ++ ++static byte pic2_reduce_color_bits(c, from, to) ++int c, from, to; ++{ ++ return ((byte) (c >> (from - to))); ++} ++ ++static pixel pic2_exchange_rg(p, colbits) ++pixel p; ++int colbits; ++{ ++ pixel rmask, gmask, bmask; ++ ++ rmask = (0xff >> (8 - colbits)) << (colbits * 2); ++ gmask = (0xff >> (8 - colbits)) << colbits; ++ bmask = (0xff >> (8 - colbits)); ++ ++ p = ((p << colbits) & rmask) ++ | ((p >> colbits) & gmask) ++ | ( p & bmask); ++ return (p); ++} ++ ++/* ++ * This function handles work memory buffer. ++ */ ++static void pic2_handle_para(pi, mode) ++struct pic2_info *pi; ++int mode; ++{ ++ static pixel *vram_prev, *vram_now, *vram_next; ++ static short *flag_now, *flag_next; ++ static short *flag2_now, *flag2_next, *flag2_next2; ++ ++ switch (mode) { ++ case 0: ++ vram_prev = pi->vram_prev; ++ vram_now = pi->vram_now; ++ vram_next = pi->vram_next; ++ flag_now = pi->flag_now; ++ flag_next = pi->flag_next; ++ flag2_now = pi->flag2_now; ++ flag2_next = pi->flag2_next; ++ flag2_next2 = pi->flag2_next2; ++ pi->vram_prev += 4; ++ pi->vram_now += 4; ++ pi->vram_next += 4; ++ pi->flag_now += 4; ++ pi->flag_next += 4; ++ pi->flag2_now += 4; ++ pi->flag2_next += 4; ++ pi->flag2_next2 += 4; ++ break; ++ case 1: ++ pi->vram_prev = vram_now; ++ pi->vram_now = vram_next; ++ pi->vram_next = vram_prev; ++ pi->flag_now = flag_next; ++ pi->flag_next = flag_now; ++ pi->flag2_now = flag2_next; ++ pi->flag2_next = flag2_next2; ++ pi->flag2_next2 = flag2_now; ++ break; ++ } ++} ++ ++/* ++ * These functions alloc/free work memory. ++ * pic2_alloc_buffer: ++ * alloc work memory buffer. ++ * pic2_free_buffer: ++ * free work memory buffer. ++ */ ++static int pic2_alloc_buffer(pi) ++struct pic2_info *pi; ++{ ++ int wid; ++ byte *p; ++ ++ if (pi->buf != NULL) ++ return (-1); ++ ++ wid = pi->block->x_wid; ++ ++ p = pi->buf = (byte *) pic2_new((wid + 8) * sizeof(pixel) * 3 // GRR POSSIBLE OVERFLOW / FIXME ++ + sizeof(pi->cache[0]) * 8 * 8 * 8 ++ + sizeof(pi->cache_pos[0]) * 8 * 8 * 8 ++ + sizeof(pi->mulu_tab[0]) * 16384 ++ + sizeof(pi->flag_now[0]) * ((wid+8) * 5), ++ "pic2_alloc_buffer"); ++ ++ pi->vram_prev = (pixel *) p; ++ p += (wid + 8) * sizeof(pixel); ++ pi->vram_now = (pixel *) p; ++ p += (wid + 8) * sizeof(pixel); ++ pi->vram_next = (pixel *) p; ++ p += (wid + 8) * sizeof(pixel); ++ pi->cache = (pixel (*)[PIC2_ARITH_CACHE]) p; ++ p += sizeof(pi->cache[0]) * 8 * 8 * 8; ++ pi->cache_pos = (unsigned short *) p; ++ p += sizeof(pi->cache_pos[0]) * 8 * 8 * 8; ++ pi->mulu_tab = (unsigned short *) p; ++ p += sizeof(pi->mulu_tab[0]) * 16384; ++ pi->flag_now = (short *) p; ++ p += sizeof(pi->flag_now[0]) * (wid + 8); ++ pi->flag_next = (short *) p; ++ p += sizeof(pi->flag_next[0]) * (wid + 8); ++ pi->flag2_now = (short *) p; ++ p += sizeof(pi->flag2_now[0]) * (wid + 8); ++ pi->flag2_next = (short *) p; ++ p += sizeof(pi->flag2_next[0]) * (wid + 8); ++ pi->flag2_next2 = (short *) p; ++ p += sizeof(pi->flag2_next2[0]) * (wid + 8); ++ return (0); ++} ++ ++static void pic2_free_buffer(pi) ++struct pic2_info *pi; ++{ ++ free(pi->buf); ++ pi->buf = NULL; ++} ++ ++/* ++ * These functions handle the file pointer. ++ * pic2_seek_file: ++ * moves the file pointer. ++ * pic2_tell_file: ++ * tells the location of the file pointer. ++ */ ++static long pic2_seek_file(pi, offset, whence) ++struct pic2_info *pi; ++long offset; ++int whence; ++{ ++ long n; ++ ++ n = fseek(pi->fp, offset, whence); ++ if (n < 0) ++ pic2_file_error(pi, PIC2_CORRUPT); ++ ++ return (n); ++} ++ ++static long pic2_tell_file(pi) ++struct pic2_info *pi; ++{ ++ return (ftell(pi->fp)); ++} ++ ++/* ++ * These functions handle file. ++ * pic2_read_file: ++ * reads data from the file. ++ * pic2_read_long: ++ * reads long word data from the file and converts to internal expression. ++ * pic2_read_short: ++ * reads word data from the file and converts to internal expression. ++ * pic2_read_char: ++ * reads byte data from the file. ++ * pic2_write_file: ++ * writes data to the file. ++ * pic2_write_long: ++ * converts long word data to common expression and writes to the file. ++ * pic2_write_short: ++ * converts word data to common expression and writes to the file. ++ * pic2_write_char: ++ * writes byte data to the file. ++ */ ++static int pic2_read_file(pi, buf, size) ++struct pic2_info *pi; ++void *buf; ++size_t size; ++{ ++ if (fread(buf, (size_t) 1, size, pi->fp) < size) ++ pic2_file_error(pi, PIC2_CORRUPT); ++ return (0); ++} ++ ++static long pic2_read_long(pi) ++struct pic2_info *pi; ++{ ++ byte buf[4]; ++ ++ if (fread(buf, (size_t) 4, (size_t) 1, pi->fp) < 1) ++ pic2_file_error(pi, PIC2_CORRUPT); ++ return (pic2_cextolong(buf)); ++} ++ ++static short pic2_read_short(pi) ++struct pic2_info *pi; ++{ ++ byte buf[2]; ++ ++ if (fread(buf, (size_t) 2, (size_t) 1, pi->fp) < 1) ++ pic2_file_error(pi, PIC2_CORRUPT); ++ return (pic2_cextoshort(buf)); ++} ++ ++static char pic2_read_char(pi) ++struct pic2_info *pi; ++{ ++ int c; ++ ++ if ((c = fgetc(pi->fp)) == EOF) ++ pic2_file_error(pi, PIC2_CORRUPT); ++ return ((char) c); ++} ++ ++static int pic2_write_file(pi, buf, size) ++struct pic2_info *pi; ++void *buf; ++size_t size; ++{ ++ if (fwrite(buf, (size_t) 1, size, pi->fp) < size) ++ pic2_error(pi, PIC2_WRITE); ++ return (0); ++} ++ ++static int pic2_write_long(pi, n) ++struct pic2_info *pi; ++long n; ++{ ++ byte buf[4]; ++ ++ pic2_longtocex(buf, n); ++ if (fwrite(buf, (size_t) 4, (size_t) 1, pi->fp) < 1) ++ pic2_error(pi, PIC2_WRITE); ++ return (0); ++} ++ ++static int pic2_write_short(pi, n) ++struct pic2_info *pi; ++int n; ++{ ++ byte buf[2]; ++ ++ pic2_shorttocex(buf, n); ++ if (fwrite(buf, (size_t) 2, (size_t) 1, pi->fp) < 1) ++ pic2_error(pi, PIC2_WRITE); ++ return (0); ++} ++ ++static int pic2_write_char(pi, c) ++struct pic2_info *pi; ++int c; ++{ ++ if (fputc(c, pi->fp) == EOF) ++ pic2_error(pi, PIC2_WRITE); ++ return (0); ++} ++ ++/* ++ * These functions access the bit stream. ++ * pic2_read_bits: ++ * reads the specified bits from the file. ++ * pic2_write_bits: ++ * writes the specified bits to the file. ++ * pic2_flush_bits: ++ * flushes bit buffer to the file. ++ */ ++static unsigned long pic2_read_bits(pi, bits) ++struct pic2_info *pi; ++int bits; ++{ ++ unsigned long r = 0; ++ ++ while (bits > 0) { ++ while (pi->bs.rest > 0 && bits > 0) { ++ r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0); ++ pi->bs.cur <<= 1; ++ pi->bs.rest--; ++ bits--; ++ } ++ if (bits > 0) { ++ int c; ++ if ((c = fgetc(pi->fp)) == EOF) ++ pic2_file_error(pi, PIC2_CORRUPT); ++ pi->bs.cur = (byte) c; ++ pi->bs.rest = 8; ++ } ++ } ++ return r; ++} ++ ++static void pic2_write_bits(pi, dat, bits) ++struct pic2_info *pi; ++unsigned long dat; ++int bits; ++{ ++ unsigned long dat_mask = 1 << (bits - 1); ++ ++ while (bits > 0) { ++ while (pi->bs.rest < 8 && bits > 0) { ++ pi->bs.cur <<= 1; ++ if (dat & dat_mask) ++ pi->bs.cur |= 1; ++ pi->bs.rest++; ++ bits--; ++ dat_mask >>= 1; ++ } ++ if (pi->bs.rest >= 8) { ++ if ((fputc((int) pi->bs.cur, pi->fp)) == EOF) ++ pic2_error(pi, PIC2_WRITE); ++ pi->bs.cur = 0; ++ pi->bs.rest = 0; ++ } ++ } ++} ++ ++static void pic2_flush_bits(pi) ++struct pic2_info *pi; ++{ ++ if (pi->bs.rest < 8) { ++ pi->bs.cur <<= 8 - pi->bs.rest; ++ if (fputc((int) pi->bs.cur, pi->fp) == EOF) ++ pic2_error(pi, PIC2_WRITE); ++ pi->bs.cur = 0; ++ pi->bs.rest = 0; ++ } ++} ++ ++/* ++ * These functions initialize or clean up structures. ++ * pic2_init_info: ++ * initializes a pic2_info structure. ++ * pic2_cleanup_pic2_info: ++ * cleans up a pic_info structure. ++ * pic2_cleanup_pinfo: ++ * cleans up a PICINFO structure. ++ */ ++static void pic2_init_info(pi) ++struct pic2_info *pi; ++{ ++ xvbzero((char *) pi, sizeof(struct pic2_info)); ++ pi->header = pic2_new(sizeof(struct pic2_header), "pic2_init_info#1"); ++ pi->block = pic2_new(sizeof(struct pic2_block), "pic2_init_info#2"); ++} ++ ++static void pic2_cleanup_pic2_info(pi, writing) ++struct pic2_info *pi; ++int writing; ++{ ++ if (!writing && pi->fp) ++ fclose(pi->fp); ++ if (pi->header) ++ free(pi->header); ++ if (pi->block) ++ free(pi->block); ++ pi->fp = NULL; ++ pi->header = NULL; ++ pi->block = NULL; ++ pi->comment = NULL; ++} ++ ++static void pic2_cleanup_pinfo(pinfo) ++PICINFO *pinfo; ++{ ++ if (pinfo->pic){ ++ free(pinfo->pic); ++ pinfo->pic = NULL; ++ } ++ if (pinfo->comment){ ++ free(pinfo->comment); ++ pinfo->comment = NULL; ++ } ++} ++ ++/* ++ * Error Handlers. ++ * pic2_memory_error: ++ * shows an error message and terminates. ++ * pic2_error: ++ * shows a non-file error message and jumps to the entry for errors. ++ * pic2_file_error: ++ * shows a file error message and jumps to the entry for errors. ++ */ ++static void pic2_memory_error(scm, fn) ++char *scm, *fn; ++{ ++ char buf[128]; ++ sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn); ++ FatalError(buf); ++} ++ ++static void pic2_error(pi, mn) ++struct pic2_info *pi; ++int mn; ++{ ++ SetISTR(ISTR_WARNING, "%s", pic2_msgs[mn]); ++ longjmp(pi->jmp, 1); ++} ++ ++static void pic2_file_error(pi, mn) ++ struct pic2_info *pi; ++ int mn; ++{ ++ if (feof(pi->fp)) ++ SetISTR(ISTR_WARNING, "%s (end of file)", pic2_msgs[mn]); ++ else ++ SetISTR(ISTR_WARNING, "%s (%s)", pic2_msgs[mn], ERRSTR(errno)); ++ longjmp(pi->jmp, 1); ++} ++ ++static void pic2_show_pic2_info(pi) ++ struct pic2_info *pi; ++{ ++ fprintf(stderr, "file size: %ld.\n", pi->fsize); ++ fprintf(stderr, "full image size: %dx%d\n", pi->x_max, pi->y_max); ++ fprintf(stderr, "number of palettes: %d\n", pi->n_pal); ++ fprintf(stderr, "depth of palettes: %d\n", pi->pal_bits); ++ fprintf(stderr, "current block position: %ld\n", pi->block_pos); ++ fprintf(stderr, "next block position: %ld\n\n", pi->next_pos); ++ ++ fprintf(stderr, "header flag: %x\n", pi->header->flag); ++ fprintf(stderr, "header size: %ld\n", pi->header->size); ++ fprintf(stderr, "x_aspect: %d, y_aspect: %d\n", ++ pi->header->x_aspect, pi->header->y_aspect); ++ fprintf(stderr, "number of color bits: %d\n\n", pi->header->depth); ++ ++ fprintf(stderr, "image block id: %s\n", pi->block->id); ++ fprintf(stderr, "image block size: %ld\n", pi->block->size); ++ fprintf(stderr, "block flag: %x\n", pi->block->flag); ++ ++ fprintf(stderr, "block image size: %dx%d\n", ++ pi->block->x_wid, pi->block->y_wid); ++ fprintf(stderr, "x_offset: %d\n", pi->block->x_offset); ++ fprintf(stderr, "y_offset: %d\n", pi->block->y_offset); ++ fprintf(stderr, "opaque color: %lx\n\n", pi->block->opaque); ++} ++ ++/* ++ * This function is similar to strncpy. ++ * But this pads with whitespace after the null character. ++ */ ++static char *pic2_strncpy(dest, src, n) ++char *dest, *src; ++size_t n; ++{ ++ char *r; ++ ++ r = dest; ++ while (n--) ++ if ((src != NULL) && (*src != '\r') && (*src != '\n') && *src) ++ *dest++ = *src++; ++ else ++ *dest++ = ' '; ++ return (r); ++} ++ ++/* ++ * These functions create a memory block. ++ */ ++static void *pic2_malloc(size, fn) ++size_t size; ++char *fn; ++{ ++ void *p; ++ ++ p = (void *) malloc(size); ++ if (p == NULL) ++ pic2_memory_error("malloc", fn); ++ return (p); ++} ++ ++static void *pic2_new(size, fn) ++size_t size; ++char *fn; ++{ ++ void *p; ++ ++ p = (void *) pic2_malloc(size, fn); ++ xvbzero((char *) p, size); ++ return (p); ++} ++ ++ ++ ++ ++/**** Stuff for PIC2Dialog box ****/ ++ ++#define TWIDE 320 ++#define THIGH 178 ++#define T_NBUTTS 2 ++#define T_BOK 0 ++#define T_BCANC 1 ++#define BUTTH 24 ++ ++static void drawTD PARM((int,int,int,int)); ++static void clickTD PARM((int,int)); ++static void doCmd PARM((int)); ++static void writePIC2 PARM((void)); ++ ++/* local variables */ ++static FILE *fp; ++static char *filename; ++static int colorType; ++static int append; ++static int x_offset; ++static int y_offset; ++static BUTT tbut[T_NBUTTS]; ++static RBUTT *typeRB; ++static RBUTT *depthRB; ++ ++ ++ ++/***************************************************/ ++void CreatePIC2W() ++{ ++ int y; ++ ++ pic2W = CreateWindow("xv pic2", "XVpic2", NULL, ++ TWIDE, THIGH, infofg, infobg, 0); ++ if (!pic2W) ++ FatalError("can't create pic2 window!"); ++ ++ XSelectInput(theDisp, pic2W, ++ ExposureMask | ButtonPressMask | KeyPressMask); ++ ++ BTCreate(&tbut[T_BOK], pic2W, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH, ++ "Ok", infofg, infobg, hicol, locol); ++ ++ BTCreate(&tbut[T_BCANC], pic2W, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH, ++ "Cancel", infofg, infobg, hicol, locol); ++ ++ y = 55; ++ typeRB = RBCreate(NULL, pic2W, 36, y, "P2SS", ++ infofg, infobg,hicol,locol); ++ RBCreate(typeRB, pic2W, 36, y+18, "P2SF", ++ infofg, infobg,hicol,locol); ++ RBCreate(typeRB, pic2W, 36, y+36, "P2BM", ++ infofg, infobg, hicol, locol); ++ RBCreate(typeRB, pic2W, 36, y+54, "P2BI", ++ infofg, infobg, hicol, locol); ++ ++ depthRB = RBCreate(NULL, pic2W, TWIDE/2-16, y, " 3bit", ++ infofg, infobg,hicol,locol); ++ RBCreate(depthRB, pic2W, TWIDE/2-16, y+18, " 6bit", ++ infofg, infobg,hicol,locol); ++ RBCreate(depthRB, pic2W, TWIDE/2-16, y+36, " 9bit", ++ infofg, infobg, hicol, locol); ++ RBCreate(depthRB, pic2W, TWIDE/2-16, y+54, "12bit", ++ infofg, infobg, hicol, locol); ++ RBCreate(depthRB, pic2W, TWIDE/4*3-16, y, "15bit", ++ infofg, infobg, hicol, locol); ++ RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+18, "18bit", ++ infofg, infobg, hicol, locol); ++ RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+36, "21bit", ++ infofg, infobg, hicol, locol); ++ RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+54, "24bit", ++ infofg, infobg, hicol, locol); ++ ++ XMapSubwindows(theDisp, pic2W); ++} ++ ++ ++/***************************************************/ ++void PIC2Dialog(vis) ++int vis; ++{ ++ if (vis) { ++ CenterMapWindow(pic2W, tbut[T_BOK].x + tbut[T_BOK].w/2, ++ tbut[T_BOK].y + tbut[T_BOK].h/2, TWIDE, THIGH); ++ } ++ else XUnmapWindow(theDisp, pic2W); ++ pic2Up = vis; ++} ++ ++ ++/***************************************************/ ++int PIC2CheckEvent(xev) ++XEvent *xev; ++{ ++ /* check event to see if it's for one of our subwindows. If it is, ++ deal accordingly and return '1'. Otherwise, return '0'. */ ++ ++ int rv; ++ rv = 1; ++ ++ if (!pic2Up) ++ return (0); ++ ++ if (xev->type == Expose) { ++ int x,y,w,h; ++ XExposeEvent *e = (XExposeEvent *) xev; ++ x = e->x; y = e->y; w = e->width; h = e->height; ++ ++ if (e->window == pic2W) drawTD(x, y, w, h); ++ else rv = 0; ++ } ++ ++ else if (xev->type == ButtonPress) { ++ XButtonEvent *e = (XButtonEvent *) xev; ++ int x,y; ++ x = e->x; y = e->y; ++ ++ if (e->button == Button1) { ++ if (e->window == pic2W) clickTD(x,y); ++ else rv = 0; ++ } /* button1 */ ++ else rv = 0; ++ } /* button press */ ++ ++ ++ else if (xev->type == KeyPress) { ++ XKeyEvent *e = (XKeyEvent *) xev; ++ char buf[128]; KeySym ks; XComposeStatus status; ++ int stlen; ++ ++ stlen = XLookupString(e,buf,128,&ks,&status); ++ buf[stlen] = '\0'; ++ ++ if (e->window == pic2W) { ++ if (stlen) { ++ if (buf[0] == '\r' || buf[0] == '\n') { /* enter */ ++ FakeButtonPress(&tbut[T_BOK]); ++ } ++ else if (buf[0] == '\033') { /* ESC */ ++ FakeButtonPress(&tbut[T_BCANC]); ++ } ++ } ++ } ++ else rv = 0; ++ } ++ else rv = 0; ++ ++ if (rv == 0 && (xev->type == ButtonPress || xev->type == KeyPress)) { ++ XBell(theDisp, 50); ++ rv = 1; /* eat it */ ++ } ++ ++ return (rv); ++} ++ ++ ++/***************************************************/ ++int PIC2SaveParams(fname, col) ++char *fname; ++int col; ++{ ++ filename = fname; ++ colorType = col; ++ ++ /* see if we can open the output file before proceeding */ ++ fp = pic2_OpenOutFile(filename, &append); ++ if (!fp) ++ return (-1); ++ ++ RBSetActive(typeRB,0,1); ++ RBSetActive(typeRB,1,1); ++ RBSetActive(typeRB,2,1); ++ RBSetActive(typeRB,3,1); ++ RBSelect(typeRB,0); ++ ++ ++ if (append) { ++ struct pic2_info pic2; ++ ++ pic2_init_info(&pic2); ++ pic2.fp = fp; ++ pic2_read_header(&pic2); ++ ++ RBSetActive(depthRB,0,0); ++ RBSetActive(depthRB,1,0); ++ RBSetActive(depthRB,2,0); ++ RBSetActive(depthRB,3,0); ++ RBSetActive(depthRB,4,0); ++ RBSetActive(depthRB,5,0); ++ RBSetActive(depthRB,6,0); ++ RBSetActive(depthRB,7,0); ++ ++ switch (pic2.header->depth) { ++ case 3: ++ RBSetActive(depthRB,0,1); ++ RBSelect(depthRB,0); ++ RBSetActive(typeRB,3,0); ++ break; ++ case 6: ++ RBSetActive(depthRB,1,1); ++ RBSelect(depthRB,1); ++ RBSetActive(typeRB,3,0); ++ break; ++ case 9: ++ RBSetActive(depthRB,2,1); ++ RBSelect(depthRB,2); ++ break; ++ case 12: ++ RBSetActive(depthRB,3,1); ++ RBSelect(depthRB,3); ++ break; ++ case 15: ++ RBSetActive(depthRB,4,1); ++ RBSelect(depthRB,4); ++ break; ++ case 18: ++ RBSetActive(depthRB,5,1); ++ RBSelect(depthRB,5); ++ RBSetActive(typeRB,3,0); ++ break; ++ case 21: ++ RBSetActive(depthRB,6,1); ++ RBSelect(depthRB,6); ++ RBSetActive(typeRB,3,0); ++ break; ++ case 24: ++ RBSetActive(depthRB,7,1); ++ RBSelect(depthRB,7); ++ RBSetActive(typeRB,3,0); ++ break; ++ default: { ++ char str[512]; ++ sprintf(str, "unsupported PIC2 file '%s'.", filename); ++ ErrPopUp(str, "\nBummer"); ++ CloseOutFile(fp, filename, 0); ++ fp = OpenOutFile(fname); ++ if (!fp) ++ return (-1); ++ break; ++ } ++ } ++ pic2_seek_file(&pic2, 0, SEEK_SET); ++ pic2_cleanup_pic2_info(&pic2, 1); ++ } else { ++ RBSetActive(depthRB,0,1); ++ RBSetActive(depthRB,1,1); ++ RBSetActive(depthRB,2,1); ++ RBSetActive(depthRB,3,1); ++ RBSetActive(depthRB,4,1); ++ RBSetActive(depthRB,5,1); ++ RBSetActive(depthRB,6,1); ++ RBSetActive(depthRB,7,1); ++ RBSelect(depthRB,7); ++ RBSetActive(typeRB,3,0); ++ } ++ return (0); ++} ++ ++ ++/***************************************************/ ++static void drawTD(x,y,w,h) ++int x,y,w,h; ++{ ++ char *title = "Save PIC2 file..."; ++ int i; ++ XRectangle xr; ++ ++ xr.x = x; xr.y = y; xr.width = w; xr.height = h; ++ XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted); ++ ++ XSetForeground(theDisp, theGC, infofg); ++ XSetBackground(theDisp, theGC, infobg); ++ ++ for (i = 0; i < T_NBUTTS; i++) ++ BTRedraw(&tbut[i]); ++ ++ ULineString(pic2W, typeRB->x-16, typeRB->y-3-DESCENT, "FormatType"); ++ ULineString(pic2W, depthRB->x-16, depthRB->y-3-DESCENT, "ColorDepth"); ++ RBRedraw(typeRB, -1); ++ RBRedraw(depthRB, -1); ++ ++ DrawString(pic2W, 20, 29, title); ++ ++ XSetClipMask(theDisp, theGC, None); ++} ++ ++static void clickTD(x,y) ++int x,y; ++{ ++ int i; ++ BUTT *bp; ++ ++ /* check BUTTs */ ++ ++ /* check the RBUTTS first, since they don't DO anything */ ++ if ((i = RBClick(typeRB, x,y)) >= 0) { ++ (void) RBTrack(typeRB, i); ++ return; ++ } else if ((i = RBClick(depthRB, x,y)) >= 0) { ++ (void) RBTrack(depthRB, i); ++ if ((2 <= i) && (i <= 4)) ++ RBSetActive(typeRB,3,1); ++ else { ++ RBSetActive(typeRB,3,0); ++ if (RBWhich(typeRB) == 3) ++ RBSelect(typeRB,0); ++ return; ++ } ++ } ++ for (i = 0; i < T_NBUTTS; i++) { ++ bp = &tbut[i]; ++ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) ++ break; ++ } ++ if (i < T_NBUTTS) /* found one */ ++ if (BTTrack(bp)) ++ doCmd(i); ++} ++ ++ ++ ++/***************************************************/ ++static void doCmd(cmd) ++int cmd; ++{ ++ switch (cmd) { ++ case T_BOK: { ++ char *fullname; ++ char buf[64], *x_offsetp, *y_offsetp; ++ static char *labels[] = { "\nOk", "\033Cancel" }; ++ XEvent event; ++ int i; ++ ++ strcpy(buf, "0,0"); ++ i = GetStrPopUp("Enter offset (x,y):", labels, 2, buf, 64, ++ "01234567890,", 1); ++ ++ if (i) ++ return; ++ if (strlen(buf)==0) ++ return; ++ ++ x_offsetp = buf; ++ y_offsetp = index(buf, ','); ++ if (!y_offsetp) ++ return; ++ *(y_offsetp++) = '\0'; ++ if ((*x_offsetp == '\0') || (*y_offsetp == '\0')) ++ return; ++ x_offset = atoi(x_offsetp); ++ y_offset = atoi(y_offsetp); ++ ++ XNextEvent(theDisp, &event); ++ HandleEvent(&event, &i); ++ ++ writePIC2(); ++ PIC2Dialog(0); ++ ++ fullname = GetDirFullName(); ++ if (!ISPIPE(fullname[0])) { ++ XVCreatedFile(fullname); ++ StickInCtrlList(0); ++ } ++ } ++ break; ++ case T_BCANC: ++ pic2_KillNullFile(fp); ++ PIC2Dialog(0); ++ break; ++ default: ++ break; ++ } ++} ++ ++ ++/*******************************************/ ++static void writePIC2() ++{ ++ int w, h, nc, rv, type, depth, ptype, pfree; ++ byte *inpix, *rmap, *gmap, *bmap; ++ ++ ++ WaitCursor(); ++ inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap); ++ ++ if (colorType == F_REDUCED) ++ colorType = F_FULLCOLOR; ++ ++ switch (RBWhich(typeRB)) { ++ case 0: type = P2SS; break; ++ case 1: type = P2SF; break; ++ case 2: type = P2BM; break; ++ case 3: type = P2BI; break; ++ default: type = P2SS; break; ++ } ++ switch (RBWhich(depthRB)) { ++ case 0: depth = 3; break; ++ case 1: depth = 6; break; ++ case 2: depth = 9; break; ++ case 3: depth = 12; break; ++ case 4: depth = 15; break; ++ case 5: depth = 18; break; ++ case 6: depth = 21; break; ++ case 7: depth = 24; break; ++ default: depth = 24; break; ++ } ++ rv = WritePIC2(fp, inpix, ptype, w, h, ++ rmap, gmap, bmap, nc, colorType, filename, ++ type, depth, x_offset, y_offset, append, picComments); ++ ++ if (CloseOutFile(fp, filename, rv) == 0) ++ DirBox(0); ++ ++ if (pfree) ++ free(inpix); ++} ++#endif /* HAVE_PIC2 */ +diff -ruN xv-3.10a-bugfixes/xvpng.c xv-3.10a-enhancements/xvpng.c +--- xv-3.10a-bugfixes/xvpng.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvpng.c 2005-04-17 15:00:08.000000000 -0700 +@@ -0,0 +1,1081 @@ ++/* ++ * xvpng.c - load and write routines for 'PNG' format pictures ++ * ++ * callable functions ++ * ++ * CreatePNGW() ++ * PNGDialog(vis) ++ * PNGCheckEvent(xev) ++ * PNGSaveParams(fname, col) ++ * LoadPNG(fname, pinfo) ++ * VersionInfoPNG() ++ */ ++ ++/*#include "copyright.h"*/ ++/* (c) 1995 by Alexander Lehmann <lehmann@mathematik.th-darmstadt.de> ++ * This file is a suplement to xv and is supplied under the same copying ++ * conditions (except the shareware part). ++ * Modified by Andreas Dilger <adilger@enel.ucalgary.ca> to fix ++ * error handling for bad PNGs, add dialogs for interlacing and ++ * compression selection, and upgrade to libpng-0.89. ++ * Modified by Greg Roelofs, TenThumbs and others to fix bugs and add ++ * features. ++ * The copyright will be passed on to JB at some future point if he ++ * so desires. ++ */ ++ ++#include "xv.h" ++ ++#ifdef HAVE_PNG ++ ++#include "png.h" ++ ++/*** Stuff for PNG Dialog box ***/ ++#define PWIDE 318 ++#define PHIGH 215 ++ ++#define DISPLAY_GAMMA 2.20 /* default display gamma */ ++#define COMPRESSION 6 /* default zlib compression level, not max ++ (Z_BEST_COMPRESSION) */ ++ ++#define HAVE_tRNS (info_ptr->valid & PNG_INFO_tRNS) ++ ++#define DWIDE 86 ++#define DHIGH 104 ++#define PFX PWIDE-93 ++#define PFY 44 ++#define PFH 20 ++ ++#define P_BOK 0 ++#define P_BCANC 1 ++#define P_NBUTTS 2 ++ ++#define BUTTH 24 ++ ++#define LF 10 /* a.k.a. '\n' on ASCII machines */ ++#define CR 13 /* a.k.a. '\r' on ASCII machines */ ++ ++/*** local functions ***/ ++static void drawPD PARM((int, int, int, int)); ++static void clickPD PARM((int, int)); ++static void doCmd PARM((int)); ++static void writePNG PARM((void)); ++static int WritePNG PARM((FILE *, byte *, int, int, int, ++ byte *, byte *, byte *, int)); ++ ++static void png_xv_error PARM((png_structp png_ptr, ++ png_const_charp message)); ++static void png_xv_warning PARM((png_structp png_ptr, ++ png_const_charp message)); ++ ++/*** local variables ***/ ++static char *filename; ++static char *fbasename; ++static int colorType; ++static int read_anything; ++static double Display_Gamma = DISPLAY_GAMMA; ++ ++static DIAL cDial, gDial; ++static BUTT pbut[P_NBUTTS]; ++static CBUTT interCB; ++static CBUTT FdefCB, FnoneCB, FsubCB, FupCB, FavgCB, FPaethCB; ++ ++/**************************************************************************/ ++/* PNG SAVE DIALOG ROUTINES ***********************************************/ ++/**************************************************************************/ ++ ++ ++/*******************************************/ ++void CreatePNGW() ++{ ++ pngW = CreateWindow("xv png", "XVPNG", NULL, ++ PWIDE, PHIGH, infofg, infobg, 0); ++ if (!pngW) FatalError("can't create PNG window!"); ++ ++ XSelectInput(theDisp, pngW, ExposureMask | ButtonPressMask | KeyPressMask); ++ ++ DCreate(&cDial, pngW, 12, 25, DWIDE, DHIGH, (double)Z_NO_COMPRESSION, ++ (double)Z_BEST_COMPRESSION, COMPRESSION, 1.0, 3.0, ++ infofg, infobg, hicol, locol, "Compression", NULL); ++ ++ DCreate(&gDial, pngW, DWIDE+27, 25, DWIDE, DHIGH, 1.0, 3.5,DISPLAY_GAMMA,0.01,0.2, ++ infofg, infobg, hicol, locol, "Disp. Gamma", NULL); ++ ++ CBCreate(&interCB, pngW, DWIDE+30, DHIGH+3*LINEHIGH+2, "interlace", ++ infofg, infobg, hicol, locol); ++ ++ CBCreate(&FdefCB, pngW, PFX, PFY, "Default", ++ infofg, infobg, hicol, locol); ++ FdefCB.val = 1; ++ ++ CBCreate(&FnoneCB, pngW, PFX, FdefCB.y + PFH + 4, "none", ++ infofg, infobg, hicol, locol); ++ CBCreate(&FsubCB, pngW, PFX, FnoneCB.y + PFH, "sub", ++ infofg, infobg, hicol, locol); ++ CBCreate(&FupCB, pngW, PFX, FsubCB.y + PFH, "up", ++ infofg, infobg, hicol, locol); ++ CBCreate(&FavgCB, pngW, PFX, FupCB.y + PFH, "average", ++ infofg, infobg, hicol, locol); ++ CBCreate(&FPaethCB, pngW, PFX, FavgCB.y + PFH, "Paeth", ++ infofg, infobg, hicol, locol); ++ ++ FnoneCB.val = FsubCB.val = FupCB.val = FavgCB.val = FPaethCB.val = 1; ++ CBSetActive(&FnoneCB, !FdefCB.val); ++ CBSetActive(&FsubCB, !FdefCB.val); ++ CBSetActive(&FupCB, !FdefCB.val); ++ CBSetActive(&FavgCB, !FdefCB.val); ++ CBSetActive(&FPaethCB, !FdefCB.val); ++ ++ BTCreate(&pbut[P_BOK], pngW, PWIDE-180-1, PHIGH-10-BUTTH-1, 80, BUTTH, ++ "Ok", infofg, infobg, hicol, locol); ++ BTCreate(&pbut[P_BCANC], pngW, PWIDE-90-1, PHIGH-10-BUTTH-1, 80, BUTTH, ++ "Cancel", infofg, infobg, hicol, locol); ++ ++ XMapSubwindows(theDisp, pngW); ++} ++ ++ ++/*******************************************/ ++void PNGDialog(vis) ++ int vis; ++{ ++ if (vis) { ++ CenterMapWindow(pngW, pbut[P_BOK].x + (int) pbut[P_BOK].w/2, ++ pbut[P_BOK].y + (int) pbut[P_BOK].h/2, ++ PWIDE, PHIGH); ++ } ++ else XUnmapWindow(theDisp, pngW); ++ pngUp = vis; ++} ++ ++ ++/*******************************************/ ++int PNGCheckEvent(xev) ++ XEvent *xev; ++{ ++ /* check event to see if it's for one of our subwindows. If it is, ++ deal accordingly, and return '1'. Otherwise, return '0' */ ++ ++ int rv; ++ rv = 1; ++ ++ if (!pngUp) return 0; ++ ++ if (xev->type == Expose) { ++ int x,y,w,h; ++ XExposeEvent *e = (XExposeEvent *) xev; ++ x = e->x; y = e->y; w = e->width; h = e->height; ++ ++ /* throw away excess expose events for 'dumb' windows */ ++ if (e->count > 0 && (e->window == cDial.win)) {} ++ ++ else if (e->window == pngW) drawPD(x, y, w, h); ++ else if (e->window == cDial.win) DRedraw(&cDial); ++ else if (e->window == gDial.win) DRedraw(&gDial); ++ else rv = 0; ++ } ++ ++ else if (xev->type == ButtonPress) { ++ XButtonEvent *e = (XButtonEvent *) xev; ++ int x,y; ++ x = e->x; y = e->y; ++ ++ if (e->button == Button1) { ++ if (e->window == pngW) clickPD(x,y); ++ else if (e->window == cDial.win) DTrack(&cDial,x,y); ++ else if (e->window == gDial.win) DTrack(&gDial,x,y); ++ else rv = 0; ++ } /* button1 */ ++ else rv = 0; ++ } /* button press */ ++ ++ else if (xev->type == KeyPress) { ++ XKeyEvent *e = (XKeyEvent *) xev; ++ char buf[128]; KeySym ks; ++ int stlen; ++ ++ stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL); ++ buf[stlen] = '\0'; ++ ++ RemapKeyCheck(ks, buf, &stlen); ++ ++ if (e->window == pngW) { ++ if (stlen) { ++ if (buf[0] == '\r' || buf[0] == '\n') { /* enter */ ++ FakeButtonPress(&pbut[P_BOK]); ++ } ++ else if (buf[0] == '\033') { /* ESC */ ++ FakeButtonPress(&pbut[P_BCANC]); ++ } ++ } ++ } ++ else rv = 0; ++ } ++ else rv = 0; ++ ++ if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) { ++ XBell(theDisp, 50); ++ rv = 1; /* eat it */ ++ } ++ ++ return rv; ++} ++ ++ ++/*******************************************/ ++void PNGSaveParams(fname, col) ++ char *fname; ++ int col; ++{ ++ filename = fname; ++ colorType = col; ++} ++ ++ ++/*******************************************/ ++static void drawPD(x, y, w, h) ++ int x, y, w, h; ++{ ++ char *title = "Save PNG file..."; ++ ++ char ctitle1[20]; ++ char *ctitle2 = "Useful range"; ++ char *ctitle3 = "is 2 - 7."; ++ char *ctitle4 = "Uncompressed = 0"; ++ ++ char *ftitle = "Row Filters:"; ++ ++ char gtitle[20]; ++ ++ int i; ++ XRectangle xr; ++ ++ xr.x = x; xr.y = y; xr.width = w; xr.height = h; ++ XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted); ++ ++ XSetForeground(theDisp, theGC, infofg); ++ XSetBackground(theDisp, theGC, infobg); ++ ++ for (i=0; i<P_NBUTTS; i++) BTRedraw(&pbut[i]); ++ ++ DrawString(pngW, 15, 6+ASCENT, title); ++ ++ sprintf(ctitle1, "Default = %d", COMPRESSION); ++ DrawString(pngW, 18, 6+DHIGH+cDial.y+ASCENT, ctitle1); ++ DrawString(pngW, 17, 6+DHIGH+cDial.y+ASCENT+LINEHIGH, ctitle2); ++ DrawString(pngW, 17, 6+DHIGH+cDial.y+ASCENT+2*LINEHIGH, ctitle3); ++ DrawString(pngW, 17, 6+DHIGH+cDial.y+ASCENT+3*LINEHIGH, ctitle4); ++ ++ sprintf(gtitle, "Default = %g", DISPLAY_GAMMA); ++ DrawString(pngW, DWIDE+30, 6+DHIGH+gDial.y+ASCENT, gtitle); ++ ++ ULineString(pngW, FdefCB.x, FdefCB.y-3-DESCENT, ftitle); ++ XDrawRectangle(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y-LINEHIGH-3, ++ 93, 8*LINEHIGH+15); ++ CBRedraw(&FdefCB); ++ XDrawLine(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y+LINEHIGH+4, ++ FdefCB.x+82, FdefCB.y+LINEHIGH+4); ++ ++ CBRedraw(&FnoneCB); ++ CBRedraw(&FupCB); ++ CBRedraw(&FsubCB); ++ CBRedraw(&FavgCB); ++ CBRedraw(&FPaethCB); ++ ++ CBRedraw(&interCB); ++ ++ XSetClipMask(theDisp, theGC, None); ++} ++ ++ ++/*******************************************/ ++static void clickPD(x,y) ++ int x,y; ++{ ++ int i; ++ BUTT *bp; ++ ++ /* check BUTTs */ ++ ++ for (i=0; i<P_NBUTTS; i++) { ++ bp = &pbut[i]; ++ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break; ++ } ++ ++ if (i<P_NBUTTS) { /* found one */ ++ if (BTTrack(bp)) doCmd(i); ++ } ++ ++ /* check CBUTTs */ ++ ++ else if (CBClick(&FdefCB,x,y)) { ++ int oldval = FdefCB.val; ++ ++ CBTrack(&FdefCB); ++ ++ if (oldval != FdefCB.val) ++ { ++ CBSetActive(&FnoneCB, !FdefCB.val); ++ CBSetActive(&FsubCB, !FdefCB.val); ++ CBSetActive(&FupCB, !FdefCB.val); ++ CBSetActive(&FavgCB, !FdefCB.val); ++ CBSetActive(&FPaethCB, !FdefCB.val); ++ ++ CBRedraw(&FnoneCB); ++ CBRedraw(&FupCB); ++ CBRedraw(&FsubCB); ++ CBRedraw(&FavgCB); ++ CBRedraw(&FPaethCB); ++ } ++ } ++ else if (CBClick(&FnoneCB,x,y)) CBTrack(&FnoneCB); ++ else if (CBClick(&FsubCB,x,y)) CBTrack(&FsubCB); ++ else if (CBClick(&FupCB,x,y)) CBTrack(&FupCB); ++ else if (CBClick(&FavgCB,x,y)) CBTrack(&FavgCB); ++ else if (CBClick(&FPaethCB,x,y)) CBTrack(&FPaethCB); ++ else if (CBClick(&interCB,x,y)) CBTrack(&interCB); ++} ++ ++ ++/*******************************************/ ++static void doCmd(cmd) ++ int cmd; ++{ ++ switch (cmd) { ++ case P_BOK: ++ { ++ char *fullname; ++ ++ writePNG(); ++ PNGDialog(0); ++ ++ fullname = GetDirFullName(); ++ if (!ISPIPE(fullname[0])) { ++ XVCreatedFile(fullname); ++ StickInCtrlList(0); ++ } ++ } ++ break; ++ ++ case P_BCANC: ++ PNGDialog(0); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++/*******************************************/ ++static void writePNG() ++{ ++ FILE *fp; ++ int w, h, nc, rv, ptype, pfree; ++ byte *inpix, *rmap, *gmap, *bmap; ++ ++ fp = OpenOutFile(filename); ++ if (!fp) return; ++ ++ fbasename = BaseName(filename); ++ ++ WaitCursor(); ++ inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap); ++ ++ rv = WritePNG(fp, inpix, ptype, w, h, rmap, gmap, bmap, nc); ++ ++ SetCursors(-1); ++ ++ if (CloseOutFile(fp, filename, rv) == 0) DirBox(0); ++ ++ if (pfree) free(inpix); ++} ++ ++ ++/*******************************************/ ++int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols) ++ FILE *fp; ++ byte *pic; ++ int ptype, w, h; ++ byte *rmap, *gmap, *bmap; ++ int numcols; ++{ ++ png_struct *png_ptr; ++ png_info *info_ptr; ++ png_color palette[256]; ++ png_textp text; ++ byte remap[256]; ++ int i, filter, linesize, pass; ++ byte *p, *png_line; ++ char software[256]; ++ char *savecmnt; ++ ++ if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, ++ png_xv_error, png_xv_warning)) == NULL) { ++ sprintf(software, "png_create_write_struct() failure in WritePNG (ver. %s)", ++ PNG_LIBPNG_VER_STRING); ++ FatalError(software); ++ } ++ ++ if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) ++ { ++ png_destroy_write_struct(&png_ptr, &info_ptr); ++ sprintf(software, "png_create_info_struct() failure in WritePNG"); ++ FatalError(software); ++ } ++ ++ if (setjmp(png_ptr->jmpbuf)) { ++ png_destroy_write_struct(&png_ptr, &info_ptr); ++ return -1; ++ } ++ ++ png_init_io(png_ptr, fp); ++ ++ png_set_compression_level(png_ptr, (int)cDial.val); ++ ++ /* Don't bother filtering if we aren't compressing the image */ ++ if (FdefCB.val) ++ { ++ if ((int)cDial.val == 0) ++ png_set_filter(png_ptr, 0, PNG_FILTER_NONE); ++ } ++ else ++ { ++ filter = FnoneCB.val ? PNG_FILTER_NONE : 0; ++ filter |= FsubCB.val ? PNG_FILTER_SUB : 0; ++ filter |= FupCB.val ? PNG_FILTER_UP : 0; ++ filter |= FavgCB.val ? PNG_FILTER_AVG : 0; ++ filter |= FPaethCB.val ? PNG_FILTER_PAETH : 0; ++ ++ png_set_filter(png_ptr, 0, filter); ++ } ++ ++ info_ptr->width = w; ++ info_ptr->height = h; ++ if (w <= 0 || h <= 0) { ++ SetISTR(ISTR_WARNING, "%s: image dimensions out of range (%dx%d)", ++ fbasename, w, h); ++ png_destroy_write_struct(&png_ptr, &info_ptr); ++ return -1; ++ } ++ ++ info_ptr->interlace_type = interCB.val ? 1 : 0; ++ ++ linesize = 0; /* quiet a compiler warning */ ++ ++ if (colorType == F_FULLCOLOR || colorType == F_REDUCED) { ++ if(ptype == PIC24) { ++ linesize = 3*w; ++ if (linesize/3 < w) { ++ SetISTR(ISTR_WARNING, "%s: image dimensions too large (%dx%d)", ++ fbasename, w, h); ++ png_destroy_write_struct(&png_ptr, &info_ptr); ++ return -1; ++ } ++ info_ptr->color_type = PNG_COLOR_TYPE_RGB; ++ info_ptr->bit_depth = 8; ++ } else { ++ linesize = w; ++ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; ++ if(numcols <= 2) ++ info_ptr->bit_depth = 1; ++ else ++ if(numcols <= 4) ++ info_ptr->bit_depth = 2; ++ else ++ if(numcols <= 16) ++ info_ptr->bit_depth = 4; ++ else ++ info_ptr->bit_depth = 8; ++ ++ for(i = 0; i < numcols; i++) { ++ palette[i].red = rmap[i]; ++ palette[i].green = gmap[i]; ++ palette[i].blue = bmap[i]; ++ } ++ info_ptr->num_palette = numcols; ++ info_ptr->palette = palette; ++ info_ptr->valid |= PNG_INFO_PLTE; ++ } ++ } ++ ++ else if(colorType == F_GREYSCALE || colorType == F_BWDITHER) { ++ info_ptr->color_type = PNG_COLOR_TYPE_GRAY; ++ if(colorType == F_BWDITHER) { ++ /* shouldn't happen */ ++ if (ptype == PIC24) FatalError("PIC24 and B/W Stipple in WritePNG()"); ++ ++ info_ptr->bit_depth = 1; ++ if(MONO(rmap[0], gmap[0], bmap[0]) > MONO(rmap[1], gmap[1], bmap[1])) { ++ remap[0] = 1; ++ remap[1] = 0; ++ } ++ else { ++ remap[0] = 0; ++ remap[1] = 1; ++ } ++ linesize = w; ++ } ++ else { ++ if(ptype == PIC24) { ++ linesize = 3*w; ++ if (linesize/3 < w) { ++ SetISTR(ISTR_WARNING, "%s: image dimensions too large (%dx%d)", ++ fbasename, w, h); ++ png_destroy_write_struct(&png_ptr, &info_ptr); ++ return -1; ++ } ++ info_ptr->bit_depth = 8; ++ } ++ else { ++ int low_precision; ++ ++ linesize = w; ++ ++ for(i = 0; i < numcols; i++) ++ remap[i] = MONO(rmap[i], gmap[i], bmap[i]); ++ ++ for(; i < 256; i++) ++ remap[i]=0; ++ ++ info_ptr->bit_depth = 8; ++ ++ /* Note that this fails most of the time because of gamma */ ++ /* try to adjust to 4-bit precision grayscale */ ++ ++ low_precision=1; ++ ++ for(i = 0; i < numcols; i++) { ++ if((remap[i] & 0x0f) * 0x11 != remap[i]) { ++ low_precision = 0; ++ break; ++ } ++ } ++ ++ if(low_precision) { ++ for(i = 0; i < numcols; i++) { ++ remap[i] &= 0xf; ++ } ++ info_ptr->bit_depth = 4; ++ ++ /* try to adjust to 2-bit precision grayscale */ ++ ++ for(i = 0; i < numcols; i++) { ++ if((remap[i] & 0x03) * 0x05 != remap[i]) { ++ low_precision = 0; ++ break; ++ } ++ } ++ } ++ ++ if(low_precision) { ++ for(i = 0; i < numcols; i++) { ++ remap[i] &= 3; ++ } ++ info_ptr->bit_depth = 2; ++ ++ /* try to adjust to 1-bit precision grayscale */ ++ ++ for(i = 0; i < numcols; i++) { ++ if((remap[i] & 0x01) * 0x03 != remap[i]) { ++ low_precision = 0; ++ break; ++ } ++ } ++ } ++ ++ if(low_precision) { ++ for(i = 0; i < numcols; i++) { ++ remap[i] &= 1; ++ } ++ info_ptr->bit_depth = 1; ++ } ++ } ++ } ++ } ++ ++ else ++ png_error(png_ptr, "Unknown colorstyle in WritePNG"); ++ ++ if ((text = (png_textp)malloc(sizeof(png_text)))) { ++ sprintf(software, "XV %s", REVDATE); ++ ++ text->compression = -1; ++ text->key = "Software"; ++ text->text = software; ++ text->text_length = strlen(text->text); ++ ++ info_ptr->max_text = 1; ++ info_ptr->num_text = 1; ++ info_ptr->text = text; ++ } ++ ++ Display_Gamma = gDial.val; /* Save the current gamma for loading */ ++ ++ info_ptr->gamma = 1.0/gDial.val; ++ info_ptr->valid |= PNG_INFO_gAMA; ++ ++ png_write_info(png_ptr, info_ptr); ++ ++ if(info_ptr->bit_depth < 8) ++ png_set_packing(png_ptr); ++ ++ pass=png_set_interlace_handling(png_ptr); ++ ++ if((png_line = malloc(linesize)) == NULL) ++ png_error(png_ptr, "cannot allocate temp image line"); ++ ++ for(i = 0; i < pass; i++) { ++ int j; ++ p = pic; ++ for(j = 0; j < h; j++) { ++ if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY) { ++ int k; ++ for(k = 0; k < w; k++) ++ png_line[k] = ptype==PIC24 ? MONO(p[k*3], p[k*3+1], p[k*3+2]) : ++ remap[p[k]]; ++ png_write_row(png_ptr, png_line); ++ } else /* RGB or palette */ ++ png_write_row(png_ptr, p); ++ if((j & 0x1f) == 0) WaitCursor(); ++ p += linesize; ++ } ++ } ++ ++ free(png_line); ++ ++ savecmnt = NULL; /* quiet a compiler warning */ ++ ++ if (text) ++ { ++ if (picComments && strlen(picComments) && ++ (savecmnt = (char *)malloc((strlen(picComments) + 1)*sizeof(char)))) { ++ png_textp tp; ++ char *comment, *key; ++ ++ strcpy(savecmnt, picComments); ++ key = savecmnt; ++ tp = text; ++ info_ptr->num_text = 0; ++ ++ comment = strchr(key, ':'); ++ ++ do { ++ /* Allocate a larger structure for comments if necessary */ ++ if (info_ptr->num_text >= info_ptr->max_text) ++ { ++ if ((tp = ++ realloc(text, (info_ptr->num_text + 2)*sizeof(png_text))) == NULL) ++ { ++ break; ++ } ++ else ++ { ++ text = tp; ++ tp = &text[info_ptr->num_text]; ++ info_ptr->max_text += 2; ++ } ++ } ++ ++ /* See if it looks like a PNG keyword from LoadPNG */ ++ /* GRR: should test for strictly < 80, right? (key = 1-79 chars only) */ ++ if(comment && comment[1] == ':' && comment - key <= 80) { ++ *(comment++) = '\0'; ++ *(comment++) = '\0'; ++ ++ /* If the comment is the 'Software' chunk XV writes, we remove it, ++ since we have already stored one */ ++ if (strcmp(key, "Software") == 0 && strncmp(comment, "XV", 2) == 0) { ++ key = strchr(comment, '\n'); ++ if(key) ++ key++; /* skip \n */ ++ comment = strchr(key, ':'); ++ } ++ /* We have another keyword and/or comment to write out */ ++ else { ++ tp->key = key; ++ tp->text = comment; ++ ++ /* We have to find the end of this comment, and the next keyword ++ if there is one */ ++ for (; NULL != (key = comment = strchr(comment, ':')); comment++) ++ if (key[1] == ':') ++ break; ++ ++ /* It looks like another keyword, go backward to the beginning */ ++ if (key) { ++ while(key > tp->text && *key != '\n') ++ key--; ++ ++ if (key > tp->text && comment - key <= 80) { ++ *key = '\0'; ++ key++; ++ } ++ } ++ ++ tp->text_length = strlen(tp->text); ++ ++ /* We don't have another keyword, so remove the last newline */ ++ if (!key && tp->text[tp->text_length - 1] == '\n') ++ { ++ tp->text[tp->text_length] = '\0'; ++ tp->text_length--; ++ } ++ ++ tp->compression = tp->text_length > 640 ? 0 : -1; ++ info_ptr->num_text++; ++ tp++; ++ } ++ } ++ /* Just a generic comment: make sure line-endings are valid for PNG */ ++ else { ++ char *p=key, *q=key; /* only deleting chars, not adding any */ ++ ++ while (*p) { ++ if (*p == CR) { /* lone CR or CR/LF: EOL either way */ ++ *q++ = LF; /* LF is the only allowed PNG line-ending */ ++ if (p[1] == LF) /* get rid of any original LF */ ++ ++p; ++ } else if (*p == LF) /* lone LF */ ++ *q++ = LF; ++ else ++ *q++ = *p; ++ ++p; ++ } ++ *q = '\0'; /* unnecessary...but what the heck */ ++ tp->key = "Comment"; ++ tp->text = key; ++ tp->text_length = q - key; ++ tp->compression = tp->text_length > 750 ? 0 : -1; ++ info_ptr->num_text++; ++ key = NULL; ++ } ++ } while (key && *key); ++ } ++ else ++ { ++ info_ptr->num_text = 0; ++ } ++ } ++ info_ptr->text = text; ++ ++ png_convert_from_time_t(&(info_ptr->mod_time), time(NULL)); ++ info_ptr->valid |= PNG_INFO_tIME; ++ ++ png_write_end(png_ptr, info_ptr); ++ fflush(fp); /* just in case we core-dump before finishing... */ ++ ++ if (text) ++ { ++ free(text); ++ /* must do this or png_destroy_write_struct() 0.97+ will free text again: */ ++ info_ptr->text = (png_textp)NULL; ++ if (savecmnt) ++ { ++ free(savecmnt); ++ savecmnt = (char *)NULL; ++ } ++ } ++ ++ png_destroy_write_struct(&png_ptr, &info_ptr); ++ ++ return 0; ++} ++ ++ ++/*******************************************/ ++int LoadPNG(fname, pinfo) ++ char *fname; ++ PICINFO *pinfo; ++/*******************************************/ ++{ ++ /* returns '1' on success */ ++ ++ FILE *fp; ++ png_struct *png_ptr; ++ png_info *info_ptr; ++ png_color_16 my_background; ++ int i,j; ++ int linesize, bufsize; ++ int filesize; ++ int pass; ++ int gray_to_rgb; ++ size_t commentsize; ++ ++ fbasename = BaseName(fname); ++ ++ pinfo->pic = (byte *) NULL; ++ pinfo->comment = (char *) NULL; ++ ++ read_anything=0; ++ ++ /* open the file */ ++ fp = xv_fopen(fname,"r"); ++ if (!fp) { ++ SetISTR(ISTR_WARNING,"%s: can't open file", fname); ++ return 0; ++ } ++ ++ /* find the size of the file */ ++ fseek(fp, 0L, 2); ++ filesize = ftell(fp); ++ fseek(fp, 0L, 0); ++ ++ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, ++ png_xv_error, png_xv_warning); ++ if(!png_ptr) { ++ fclose(fp); ++ FatalError("malloc failure in LoadPNG"); ++ } ++ ++ info_ptr = png_create_info_struct(png_ptr); ++ ++ if(!info_ptr) { ++ fclose(fp); ++ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); ++ FatalError("malloc failure in LoadPNG"); ++ } ++ ++ if(setjmp(png_ptr->jmpbuf)) { ++ fclose(fp); ++ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); ++ if(!read_anything) { ++ if(pinfo->pic) { ++ free(pinfo->pic); ++ pinfo->pic = NULL; ++ } ++ if(pinfo->comment) { ++ free(pinfo->comment); ++ pinfo->comment = NULL; ++ } ++ } ++ return read_anything; ++ } ++ ++ png_init_io(png_ptr, fp); ++ png_read_info(png_ptr, info_ptr); ++ ++ pinfo->w = pinfo->normw = info_ptr->width; ++ pinfo->h = pinfo->normh = info_ptr->height; ++ if (pinfo->w <= 0 || pinfo->h <= 0) { ++ SetISTR(ISTR_WARNING, "%s: image dimensions out of range (%dx%d)", ++ fbasename, pinfo->w, pinfo->h); ++ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); ++ return read_anything; ++ } ++ ++ pinfo->frmType = F_PNG; ++ ++ sprintf(pinfo->fullInfo, "PNG, %d bit ", ++ info_ptr->bit_depth * info_ptr->channels); ++ ++ switch(info_ptr->color_type) { ++ case PNG_COLOR_TYPE_PALETTE: ++ strcat(pinfo->fullInfo, "palette color"); ++ break; ++ ++ case PNG_COLOR_TYPE_GRAY: ++ strcat(pinfo->fullInfo, "grayscale"); ++ break; ++ ++ case PNG_COLOR_TYPE_GRAY_ALPHA: ++ strcat(pinfo->fullInfo, "grayscale+alpha"); ++ break; ++ ++ case PNG_COLOR_TYPE_RGB: ++ strcat(pinfo->fullInfo, "truecolor"); ++ break; ++ ++ case PNG_COLOR_TYPE_RGB_ALPHA: ++ strcat(pinfo->fullInfo, "truecolor+alpha"); ++ break; ++ } ++ ++ sprintf(pinfo->fullInfo + strlen(pinfo->fullInfo), ++ ", %sinterlaced. (%d bytes)", ++ info_ptr->interlace_type ? "" : "non-", filesize); ++ ++ sprintf(pinfo->shrtInfo, "%lux%lu PNG", info_ptr->width, info_ptr->height); ++ ++ if (info_ptr->bit_depth < 8) ++ png_set_packing(png_ptr); ++ ++ if (info_ptr->valid & PNG_INFO_gAMA) ++ png_set_gamma(png_ptr, Display_Gamma, info_ptr->gamma); ++ else ++ png_set_gamma(png_ptr, Display_Gamma, 0.45); ++ ++ gray_to_rgb = 0; /* quiet a compiler warning */ ++ ++ if (have_imagebg) { ++ if (info_ptr->bit_depth == 16) { ++ my_background.red = imagebgR; ++ my_background.green = imagebgG; ++ my_background.blue = imagebgB; ++ my_background.gray = imagebgG; /* only used if all three equal... */ ++ } else { ++ my_background.red = (imagebgR >> 8); ++ my_background.green = (imagebgG >> 8); ++ my_background.blue = (imagebgB >> 8); ++ my_background.gray = my_background.green; ++ } ++ png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, ++ 0, Display_Gamma); ++ if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA || ++ (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && HAVE_tRNS)) && ++ (imagebgR != imagebgG || imagebgR != imagebgB)) /* i.e., colored bg */ ++ { ++ png_set_gray_to_rgb(png_ptr); ++ png_set_expand(png_ptr); ++ gray_to_rgb = 1; ++ } ++ } else { ++ if (info_ptr->valid & PNG_INFO_bKGD) { ++ png_set_background(png_ptr, &info_ptr->background, ++ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); ++ } else { ++ my_background.red = my_background.green = my_background.blue = ++ my_background.gray = 0; ++ png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, ++ 0, Display_Gamma); ++ } ++ } ++ ++ if (info_ptr->bit_depth == 16) ++ png_set_strip_16(png_ptr); ++ ++ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || ++ info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ++ { ++ if (info_ptr->bit_depth == 1) ++ pinfo->colType = F_BWDITHER; ++ else ++ pinfo->colType = F_GREYSCALE; ++ png_set_expand(png_ptr); ++ } ++ ++ pass=png_set_interlace_handling(png_ptr); ++ ++ png_read_update_info(png_ptr, info_ptr); ++ ++ if(info_ptr->color_type == PNG_COLOR_TYPE_RGB || ++ info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || gray_to_rgb) ++ { ++ linesize = 3 * pinfo->w; ++ if (linesize/3 < pinfo->w) { /* know pinfo->w > 0 (see above) */ ++ SetISTR(ISTR_WARNING, "%s: image dimensions too large (%dx%d)", ++ fbasename, pinfo->w, pinfo->h); ++ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); ++ return read_anything; ++ } ++ pinfo->colType = F_FULLCOLOR; ++ pinfo->type = PIC24; ++ } else { ++ linesize = pinfo->w; ++ pinfo->type = PIC8; ++ if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY || ++ info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { ++ for(i = 0; i < 256; i++) ++ pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i; ++ } else { ++ pinfo->colType = F_FULLCOLOR; ++ for(i = 0; i < info_ptr->num_palette; i++) { ++ pinfo->r[i] = info_ptr->palette[i].red; ++ pinfo->g[i] = info_ptr->palette[i].green; ++ pinfo->b[i] = info_ptr->palette[i].blue; ++ } ++ } ++ } ++ ++ bufsize = linesize * pinfo->h; ++ if (bufsize/linesize < pinfo->h) { /* know linesize, pinfo->h > 0 (above) */ ++ SetISTR(ISTR_WARNING, "%s: image dimensions too large (%dx%d)", ++ fbasename, pinfo->w, pinfo->h); ++ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); ++ return read_anything; ++ } ++ pinfo->pic = calloc((size_t)bufsize, (size_t)1); ++ ++ if(!pinfo->pic) { ++ png_error(png_ptr, "can't allocate space for PNG image"); ++ } ++ ++ png_start_read_image(png_ptr); ++ ++ for(i = 0; i < pass; i++) { ++ byte *p = pinfo->pic; ++ for(j = 0; j < pinfo->h; j++) { ++ png_read_row(png_ptr, p, NULL); ++ read_anything = 1; ++ if((j & 0x1f) == 0) WaitCursor(); ++ p += linesize; ++ } ++ } ++ ++ png_read_end(png_ptr, info_ptr); ++ ++ if(info_ptr->num_text > 0) { ++ commentsize = 1; ++ ++ for(i = 0; i < info_ptr->num_text; i++) ++ commentsize += strlen(info_ptr->text[i].key) + 1 + ++ info_ptr->text[i].text_length + 2; ++ ++ if((pinfo->comment = malloc(commentsize)) == NULL) { ++ png_warning(png_ptr,"can't allocate comment string"); ++ } ++ else { ++ pinfo->comment[0] = '\0'; ++ for(i = 0; i < info_ptr->num_text; i++) { ++ strcat(pinfo->comment, info_ptr->text[i].key); ++ strcat(pinfo->comment, "::"); ++ strcat(pinfo->comment, info_ptr->text[i].text); ++ strcat(pinfo->comment, "\n"); ++ } ++ } ++ } ++ ++ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); ++ ++ fclose(fp); ++ ++ return 1; ++} ++ ++ ++/*******************************************/ ++static void ++png_xv_error(png_ptr, message) ++ png_structp png_ptr; ++ png_const_charp message; ++{ ++ SetISTR(ISTR_WARNING,"%s: libpng error: %s", fbasename, message); ++ ++ longjmp(png_ptr->jmpbuf, 1); ++} ++ ++ ++/*******************************************/ ++static void ++png_xv_warning(png_ptr, message) ++ png_structp png_ptr; ++ png_const_charp message; ++{ ++ if (!png_ptr) ++ return; ++ ++ SetISTR(ISTR_WARNING,"%s: libpng warning: %s", fbasename, message); ++} ++ ++ ++/*******************************************/ ++void ++VersionInfoPNG() /* GRR 19980605 */ ++{ ++ fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", ++ PNG_LIBPNG_VER_STRING, png_libpng_ver); ++ fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n", ++ ZLIB_VERSION, zlib_version); ++} ++ ++#endif /* HAVE_PNG */ +diff -ruN xv-3.10a-bugfixes/xvpopup.c xv-3.10a-enhancements/xvpopup.c +--- xv-3.10a-bugfixes/xvpopup.c 2004-05-16 18:04:13.000000000 -0700 ++++ xv-3.10a-enhancements/xvpopup.c 2005-04-25 08:21:34.000000000 -0700 +@@ -23,7 +23,7 @@ + #define OMIT_ICON_BITS + #include "bits/icon" /* icon_bits[] not used, but icon_width/height are */ + +-#define PUWIDE 400 ++#define PUWIDE 480 + #define PUHIGH 170 + + #define PAD_PUWIDE 480 +@@ -201,14 +201,14 @@ + + if (!padHaveDooDads) { + DCreate(&padWDial, popW, 16, puhigh-16-100-1,75,100, +- 1, 2048, pWIDE, 10, ++ 1.0, 2048.0, (double)pWIDE, 1.0, 10.0, + infofg, infobg, hicol, locol, "Width", NULL); + DCreate(&padHDial, popW, 16+1+75, puhigh-16-100-1,75,100, +- 1, 2048, pHIGH, 10, ++ 1.0, 2048.0, (double)pHIGH, 1.0, 10.0, + infofg, infobg, hicol, locol, "Height", NULL); + + DCreate(&padODial, popW, 16+1+75+75+9, puhigh-16-100-1,75,100, +- 0, 100, 100, 10, ++ 0.0, 100.0, 100.0, 1.0, 10.0, + infofg, infobg, hicol, locol, "Opaque", NULL); + + MBCreate(&padMthdMB, popW, 100-2+44, 10, 140, 19, NULL, +@@ -259,9 +259,9 @@ + else if (poptyp == ISPAD) { + BTSetActive(&bts[0], (int) strlen(gsBuf)); + i = pWIDE * 3; RANGE(i,2048,9999); +- DSetRange(&padWDial, 1, i, padWDial.val, 10); ++ DSetRange(&padWDial, 1.0, (double)i, padWDial.val, 1.0, 10.0); + i = pHIGH * 3; RANGE(i,2048,9999); +- DSetRange(&padHDial, 1, i, padHDial.val, 10); ++ DSetRange(&padHDial, 1.0, (double)i, padHDial.val, 1.0, 10.0); + + DSetActive(&padWDial, (padMode!=PAD_LOAD)); /* DSetRange activates dial */ + DSetActive(&padHDial, (padMode!=PAD_LOAD)); +@@ -287,15 +287,19 @@ + /* center first button in window around mouse position, with constraint that + window be fully on the screen */ + +- CenterMapWindow(popW, 40 + bts[0].x, BUTTH/2 + bts[0].y, puwide, puhigh); + popUp = poptyp; ++ if (startGrab == 2) ++ startGrab = 4; ++ else { ++ CenterMapWindow(popW, 40 + bts[0].x, BUTTH/2 + bts[0].y, puwide, puhigh); + +- /* MUST wait for VisibilityNotify event to come in, else we run the risk +- of UnMapping the window *before* the Map request completed. This +- appears to be bad, (It leaves an empty window frame up.) though it +- generally only happens on slow servers. Better safe than screwed... */ ++ /* MUST wait for VisibilityNotify event to come in, else we run the risk ++ of UnMapping the window *before* the Map request completed. This ++ appears to be bad, (It leaves an empty window frame up.) though it ++ generally only happens on slow servers. Better safe than screwed... */ + +- XWindowEvent(theDisp, popW, VisibilityChangeMask, &event); ++ XWindowEvent(theDisp, popW, VisibilityChangeMask, &event); ++ } + + /* block until this window gets closed */ + while (popUp) { +@@ -466,9 +470,9 @@ + changedGSBuf(); /* careful! popW doesn't exist yet! */ + + if (padHaveDooDads) { +- oldW = padWDial.val; +- oldH = padHDial.val; +- oldO = padODial.val; ++ oldW = (int)padWDial.val; ++ oldH = (int)padHDial.val; ++ oldO = (int)padODial.val; + } + else { oldW = pWIDE; oldH = pHIGH; oldO = 100; } + +@@ -487,9 +491,9 @@ + } + + if (rv == 1) { /* cancelled: restore normal values */ +- DSetVal(&padWDial, oldW); +- DSetVal(&padHDial, oldH); +- DSetVal(&padODial, oldO); ++ DSetVal(&padWDial, (double)oldW); ++ DSetVal(&padHDial, (double)oldH); ++ DSetVal(&padODial, (double)oldO); + } + + XUnmapWindow(theDisp, padWDial.win); +@@ -499,9 +503,9 @@ + /* load up return values */ + *pMode = padMode; + *pStr = padBuf; +- *pWide = padWDial.val; +- *pHigh = padHDial.val; +- *pOpaque = padODial.val; ++ *pWide = (int)padWDial.val; ++ *pHigh = (int)padHDial.val; ++ *pOpaque = (int)padODial.val; + *pOmode = padOMode; + + return rv; +@@ -956,14 +960,14 @@ + int x,y; + { + int i; +- BUTT *bp; ++ BUTT *bp = NULL; + + for (i=0; i<nbts; i++) { + bp = &bts[i]; + if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break; + } + +- if (i<nbts && BTTrack(bp)) { ++ if (i<nbts && bp && BTTrack(bp)) { + popUp = 0; selected = i; return; + } + +@@ -972,8 +976,8 @@ + else if (popUp == ISPAD) { + if (PTINRECT(x, y, padDButt.x, padDButt.y, padDButt.w, padDButt.h)) { + if (BTTrack(&padDButt)) { +- DSetVal(&padWDial, pWIDE); +- DSetVal(&padHDial, pHIGH); ++ DSetVal(&padWDial, (double)pWIDE); ++ DSetVal(&padHDial, (double)pHIGH); + } + } + +@@ -1105,7 +1109,7 @@ + } + + +- else if (c=='\010' || c=='\177') { /* BS or DEL */ ++ else if (c=='\010') { /* BS */ + if (gsCurPos==0) return 1; /* at beginning of str */ + xvbcopy(&gsBuf[gsCurPos], &gsBuf[gsCurPos-1], (size_t) len-gsCurPos+1); + gsCurPos--; +@@ -1128,7 +1132,7 @@ + gsCurPos = len; + } + +- else if (c=='\004') { /* ^D: delete character at gsCurPos */ ++ else if (c=='\004' || c=='\177') { /* ^D or DEL: delete character at gsCurPos */ + if (gsCurPos==len) return 1; + xvbcopy(&gsBuf[gsCurPos+1], &gsBuf[gsCurPos], (size_t) len-gsCurPos); + } +diff -ruN xv-3.10a-bugfixes/xvps.c xv-3.10a-enhancements/xvps.c +--- xv-3.10a-bugfixes/xvps.c 2005-03-30 08:18:17.000000000 -0800 ++++ xv-3.10a-enhancements/xvps.c 2005-04-17 14:45:28.000000000 -0700 +@@ -142,9 +142,9 @@ + CBCreate(&encapsCB, psW, 240, 7, "preview", infofg, infobg, hicol, locol); + CBCreate(&pscompCB, psW, 331, 7, "compress", infofg, infobg, hicol, locol); + +- DCreate(&xsDial, psW, 240, 30, 80, 100, 10, 800, 100, 5, ++ DCreate(&xsDial, psW, 240, 30, 80, 100, 10.0, 800.0, 100.0, 0.5, 5.0, + infofg, infobg, hicol, locol, "Width", "%"); +- DCreate(&ysDial, psW, 331, 30, 80, 100, 10, 800, 100, 5, ++ DCreate(&ysDial, psW, 331, 30, 80, 100, 10.0, 800.0, 100.0, 0.5, 5.0, + infofg, infobg, hicol, locol, "Height", "%"); + xsDial.drawobj = changedScale; + ysDial.drawobj = changedScale; +@@ -239,10 +239,10 @@ + + if (rd_int("psres")) { /* xv.psres: default paper resolution */ + if (def_int >= 10 && def_int <= 720) { +- int i = (int) ((PIX2INCH * 100) / def_int); ++ double v = (PIX2INCH * 100) / def_int; + +- DSetVal(&xsDial, i); +- DSetVal(&ysDial, i); ++ DSetVal(&xsDial, v); ++ DSetVal(&ysDial, v); + } + } + +@@ -839,7 +839,7 @@ + if (scx < scy) { sz_iny = h * scx; } + else { sz_inx = w * scy; } + +- DSetVal(&xsDial, (int) ((100 * (sz_inx * PIX2INCH) / w) + .5)); ++ DSetVal(&xsDial, 100 * (sz_inx * PIX2INCH) / w); + DSetVal(&ysDial, xsDial.val); + + sz_inx = (double) w / PIX2INCH * (xsDial.val / 100.0); +@@ -1561,9 +1561,9 @@ + the first one is loaded (but not deleted) */ + + #ifdef GS_PATH +- char tmp[512], gscmd[512], cmdstr[512], tmpname[64]; ++ #define CMDSIZE 1024 ++ char tmp[512], gscmd[512], cmdstr[CMDSIZE], tmpname[64]; + int gsresult, nump, i, filetype, doalert, epsf; +- char *rld; + #endif + + pinfo->pic = (byte *) NULL; +@@ -1596,7 +1596,7 @@ + /* build 'gscmd' string */ + + #ifndef VMS /* VMS needs quotes around mixed case command lines */ +- sprintf(gscmd, "%s -sDEVICE=%s -r%d -q -dNOPAUSE -sOutputFile=%s%%d ", ++ sprintf(gscmd, "%s -sDEVICE=%s -r%d -q -dSAFER -dNOPAUSE -sOutputFile=%s%%d ", + GS_PATH, gsDev, gsRes, tmpname); + #else + sprintf(gscmd, +@@ -1734,32 +1734,48 @@ + + /******************************************************************/ + #ifdef GS_PATH +-void buildCmdStr(str, gscmd, fname, quick, epsf) +- char *str, *gscmd, *fname; ++void buildCmdStr(str, gscmd, xname, quick, epsf) ++ char *str, *gscmd, *xname; + int quick, epsf; + { + /* note 'epsf' set only on files that don't have a showpage cmd */ ++ char *x, *y, *fname; ++ ++ x = (char *) malloc((5 * strlen(xname))+3); ++ if (!x) ++ FatalError("malloc failure in xvps.c buildCmdStr"); ++ fname = x; ++ *x++ = 0x27; ++ ++ for (y = xname; *y; ++y) { ++ if (0x27 == *y) { ++ strcpy(x, "'\"'\"'"); ++ x += strlen(x); ++ } else *x++ = *y; ++ } ++ strcpy (x, "'"); + + #ifndef VMS + +- if (epsf) sprintf(str, "echo '\n showpage ' | cat '%s' - | %s -", ++ if (epsf) snprintf(str, CMDSIZE, "echo '\n showpage ' | cat %s - | %s -", + fname, gscmd); + +- else if (quick) sprintf(str, "echo '%s' | cat - '%s' | %s -", ++ else if (quick) snprintf(str, CMDSIZE, "echo %s | cat - %s | %s -", + "/showpage { showpage quit } bind def", + fname, gscmd); + +- else sprintf(str, "%s -- %s", gscmd, fname); ++ else snprintf(str, CMDSIZE, "%s -- %s", gscmd, fname); + + #else /* VMS */ + /* VMS doesn't have pipes or an 'echo' command and GS doesn't like +- Unix-style file names as input files in the VMS version */ ++ Unix-style filenames as input files in the VMS version */ + strcat(tmp, " -- "); + rld = strrchr(fname, '/'); /* Pointer to last '/' */ + if (rld) rld++; /* Pointer to filename */ + else rld = fname; /* No path - use original string */ + strcat(tmp, rld); + #endif /* VMS */ ++ free(fname); + } + #endif /* GS_PATH */ + +diff -ruN xv-3.10a-bugfixes/xvrle.c xv-3.10a-enhancements/xvrle.c +--- xv-3.10a-bugfixes/xvrle.c 2005-03-29 23:29:14.000000000 -0800 ++++ xv-3.10a-enhancements/xvrle.c 2004-05-16 18:07:46.000000000 -0700 +@@ -43,7 +43,7 @@ + byte bgcol[256]; + byte maps[3][256]; + int xpos, ypos, w, h, flags, ncolors, pixelbits, ncmap, cmaplen; +- int cmtlen, npixels, bufsize=0; ++ int cmtlen; + byte *img; + long filesize; + char *bname, *errstr; +@@ -176,44 +176,32 @@ + + errstr = NULL; + if (ncolors == 0 || ncolors == 2) +- errstr = "Unsupported number of channels in RLE file"; ++ errstr = "Unsupt. # of channels in RLE file.\n"; + + if (pixelbits != 8) +- errstr = "Only 8-bit pixels supported in RLE files"; ++ errstr = "Only 8-bit pixels supported in RLE files.\n"; + + if (ncmap==0 || ncmap==1 || ncmap == 3 || ncmap == ncolors) { /* ok */ } +- else errstr = "Invalid number of colormap channels in RLE file"; ++ else errstr = "Invalid # of colormap channels in RLE file.\n"; + +- npixels = w * h; +- if (w <= 0 || h <= 0 || npixels/w != h) +- errstr = "RLE image dimensions out of range"; ++ if (w<1 || h<1) ++ errstr = "Bogus size in RLE header.\n"; + + + if (errstr) { + fclose(fp); +- if (pinfo->comment) +- free(pinfo->comment); +- pinfo->comment = (char *) NULL; ++ if (pinfo->comment) free(pinfo->comment); pinfo->comment = (char *) NULL; + return rleError(bname, errstr); + } + + + /* allocate image memory */ +- if (ncolors == 1) +- img = (byte *) calloc((size_t) npixels, (size_t) 1); +- else { +- bufsize = 3*npixels; +- if (bufsize/3 != npixels) +- return rleError(bname, "RLE image dimensions out of range"); +- img = (byte *) calloc((size_t) bufsize, (size_t) 1); +- } +- ++ if (ncolors == 1) img = (byte *) calloc((size_t) w * h, (size_t) 1); ++ else img = (byte *) calloc((size_t) w * h * 3, (size_t) 1); + if (!img) { + fclose(fp); +- if (pinfo->comment) +- free(pinfo->comment); +- pinfo->comment = (char *) NULL; +- return rleError(bname, "Unable to allocate RLE image data"); ++ if (pinfo->comment) free(pinfo->comment); pinfo->comment = (char *) NULL; ++ return rleError(bname, "unable to allocate image data.\n"); + } + + +@@ -221,10 +209,10 @@ + if ((flags & H_CLEARFIRST) && !(flags & H_NO_BACKGROUND)) { + byte *ip; + if (ncolors == 1) { +- for (i=0, ip=img; i<npixels; i++, ip++) *ip = bgcol[0]; ++ for (i=0, ip=img; i<w*h; i++, ip++) *ip = bgcol[0]; + } + else { +- for (i=0, ip=img; i<npixels; i++) ++ for (i=0, ip=img; i<w*h; i++) + for (j=0; j<3; j++, ip++) *ip = bgcol[j]; + } + } +@@ -242,7 +230,7 @@ + if (ncmap) { + byte *ip; + int imagelen, cmask; +- imagelen = (ncolors==1) ? npixels : bufsize; ++ imagelen = (ncolors==1) ? w*h : w*h*3; + cmask = (cmaplen-1); + + if (ncmap == 1) { /* single gamma curve */ +@@ -250,7 +238,7 @@ + } + + else if (ncmap >= 3 && ncolors >=3) { /* one curve per band */ +- for (i=0, ip=img; i<npixels; i++) { ++ for (i=0, ip=img; i<w*h; i++) { + *ip = maps[0][*ip & cmask]; ip++; + *ip = maps[1][*ip & cmask]; ip++; + *ip = maps[2][*ip & cmask]; ip++; +diff -ruN xv-3.10a-bugfixes/xvroot.c xv-3.10a-enhancements/xvroot.c +--- xv-3.10a-bugfixes/xvroot.c 2004-05-16 18:04:21.000000000 -0700 ++++ xv-3.10a-enhancements/xvroot.c 2004-05-16 18:07:52.000000000 -0700 +@@ -44,6 +44,7 @@ + case RM_MIRROR: + case RM_IMIRROR: rpixw = 2*eWIDE; rpixh = 2*eHIGH; break; + case RM_CSOLID: ++ case RM_UPLEFT: + case RM_CWARP: + case RM_CBRICK: rpixw = dispWIDE; rpixh = dispHIGH; break; + +@@ -101,7 +102,7 @@ + + + else if (rmode == RM_CENTER || rmode == RM_CENTILE || rmode == RM_CSOLID || +- rmode == RM_CWARP || rmode == RM_CBRICK) { ++ rmode == RM_CWARP || rmode == RM_CBRICK || rmode == RM_UPLEFT) { + /* do some stuff to set up the border around the picture */ + + if (rmode != RM_CENTILE) { +@@ -138,6 +139,12 @@ + + else if (rmode == RM_CSOLID) { } + ++ else if (rmode == RM_UPLEFT) { ++ ++ XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, 0,0, ++ (u_int) eWIDE, (u_int) eHIGH); ++ } ++ + else if (rmode == RM_CWARP) { /* warp effect */ + XSetForeground(theDisp, theGC, rootfg); + for (i=0; i<=dispWIDE; i+=8) +@@ -157,7 +164,7 @@ + + + /* draw the image centered on top of the background */ +- if (rmode != RM_CENTILE) ++ if ((rmode != RM_CENTILE) && (rmode != RM_UPLEFT)) + XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, + ((int) dispWIDE-eWIDE)/2, ((int) dispHIGH-eHIGH)/2, + (u_int) eWIDE, (u_int) eHIGH); +diff -ruN xv-3.10a-bugfixes/xvsmooth.c xv-3.10a-enhancements/xvsmooth.c +--- xv-3.10a-bugfixes/xvsmooth.c 2004-05-16 18:04:28.000000000 -0700 ++++ xv-3.10a-enhancements/xvsmooth.c 2004-05-16 18:07:59.000000000 -0700 +@@ -105,7 +105,7 @@ + /* we can save a lot of time by precomputing cxtab[] and pxtab[], both + dwide arrays of ints that contain values for the equations: + cx = (ex * swide) / dwide; +- px = ((ex * swide * 100) / dwide) - (cx * 100) - 50; */ ++ px = ((ex * swide * 128) / dwide) - (cx * 128) - 64; */ + + cxtab = (int *) malloc(dwide * sizeof(int)); + if (!cxtab) { free(pic24); return NULL; } +@@ -115,8 +115,8 @@ + + for (ex=0; ex<dwide; ex++) { + cxtab[ex] = (ex * swide) / dwide; +- pxtab[ex] = (((ex * swide)* 100) / dwide) +- - (cxtab[ex] * 100) - 50; ++ pxtab[ex] = (((ex * swide)* 128) / dwide) ++ - (cxtab[ex] * 128) - 64; + } + + for (ey=0; ey<dhigh; ey++) { +@@ -125,7 +125,7 @@ + ProgressMeter(0, (dhigh)-1, ey, "Smooth"); + + cy = (ey * shigh) / dhigh; +- py = (((ey * shigh) * 100) / dhigh) - (cy * 100) - 50; ++ py = (((ey * shigh) * 128) / dhigh) - (cy * 128) - 64; + if (py<0) { y1 = cy-1; if (y1<0) y1=0; } + else { y1 = cy+1; if (y1>shigh-1) y1=shigh-1; } + +@@ -172,30 +172,30 @@ + else { + /* compute weighting factors */ + apx = abs(px); apy = abs(py); +- pA = (apx * apy) / 100; +- pB = (apy * (100 - apx)) / 100; +- pC = (apx * (100 - apy)) / 100; +- pD = 100 - (pA + pB + pC); ++ pA = (apx * apy) >> 7; /* div 128 */ ++ pB = (apy * (128 - apx)) >> 7; /* div 128 */ ++ pC = (apx * (128 - apy)) >> 7; /* div 128 */ ++ pD = 128 - (pA + pB + pC); + + if (is24) { +- *pp++ = ((int) (pA * rA))/100 + ((int) (pB * rB))/100 + +- ((int) (pC * rC))/100 + ((int) (pD * rD))/100; ++ *pp++ = (((int) (pA * rA))>>7) + (((int) (pB * rB))>>7) + ++ (((int) (pC * rC))>>7) + (((int) (pD * rD))>>7); + +- *pp++ = ((int) (pA * gA))/100 + ((int) (pB * gB))/100 + +- ((int) (pC * gC))/100 + ((int) (pD * gD))/100; ++ *pp++ = (((int) (pA * gA))>>7) + (((int) (pB * gB))>>7) + ++ (((int) (pC * gC))>>7) + (((int) (pD * gD))>>7); + +- *pp++ = ((int) (pA * bA))/100 + ((int) (pB * bB))/100 + +- ((int) (pC * bC))/100 + ((int) (pD * bD))/100; ++ *pp++ = (((int) (pA * bA))>>7) + (((int) (pB * bB))>>7) + ++ (((int) (pC * bC))>>7) + (((int) (pD * bD))>>7); + } + else { /* 8-bit pic */ +- *pp++ = ((int) (pA * rmap[cA]))/100 + ((int)(pB * rmap[cB]))/100 + +- ((int) (pC * rmap[cC]))/100 + ((int)(pD * rmap[cD]))/100; ++ *pp++ = (((int)(pA * rmap[cA]))>>7) + (((int)(pB * rmap[cB]))>>7) + ++ (((int)(pC * rmap[cC]))>>7) + (((int)(pD * rmap[cD]))>>7); + +- *pp++ = ((int) (pA * gmap[cA]))/100 + ((int)(pB * gmap[cB]))/100 + +- ((int) (pC * gmap[cC]))/100 + ((int)(pD * gmap[cD]))/100; ++ *pp++ = (((int)(pA * gmap[cA]))>>7) + (((int)(pB * gmap[cB]))>>7) + ++ (((int)(pC * gmap[cC]))>>7) + (((int)(pD * gmap[cD]))>>7); + +- *pp++ = ((int)(pA * bmap[cA]))/100 + ((int)(pB * bmap[cB]))/100 + +- ((int)(pC * bmap[cC]))/100 + ((int)(pD * bmap[cD]))/100; ++ *pp++ = (((int)(pA * bmap[cA]))>>7) + (((int)(pB * bmap[cB]))>>7) + ++ (((int)(pC * bmap[cC]))>>7) + (((int)(pD * bmap[cD]))>>7); + } + } + } +diff -ruN xv-3.10a-bugfixes/xvtext.c xv-3.10a-enhancements/xvtext.c +--- xv-3.10a-bugfixes/xvtext.c 2004-05-16 18:04:38.000000000 -0700 ++++ xv-3.10a-enhancements/xvtext.c 2005-05-01 13:04:23.000000000 -0700 +@@ -19,9 +19,13 @@ + #include "copyright.h" + + #include "xv.h" ++#ifdef TV_MULTILINGUAL ++#include "xvml.h" ++#endif + +- +-#define BUTTW 80 ++#define BUTTW1 80 ++#define BUTTW2 60 ++#define BUTTW3 110 + #define BUTTH 24 + + #define TOPMARGIN 30 /* from top of window to top of text window */ +@@ -36,11 +40,28 @@ + #define TV_ASCII 0 + #define TV_HEX 1 + #define TV_CLOSE 2 +-#define TV_NBUTTS 3 + ++#define TV_E_NBUTTS 3 ++ ++#ifdef TV_L10N ++# define TV_RESCAN 3 ++# define TV_USASCII 4 ++# define TV_JIS 5 ++# define TV_EUCJ 6 ++# define TV_MSCODE 7 ++ ++# define TV_J_NBUTTS 8 ++#endif + + #define TITLELEN 128 + ++#ifdef TV_MULTILINGUAL ++struct coding_spec { ++ struct coding_system coding_system; ++ char *(*converter)PARM((char *, int, int *)); ++}; ++#endif ++ + /* data needed per text window */ + typedef struct { Window win, textW; + int vis, wasvis; +@@ -57,16 +78,89 @@ + int chwide, chhigh; /* size of textW, in chars */ + int hexmode; /* true if disp Hex, else Ascii */ + SCRL vscrl, hscrl; +- BUTT but[TV_NBUTTS], nopBut; ++#ifdef TV_L10N ++ int code; /* current character code */ ++ BUTT but[TV_J_NBUTTS], nopBut; ++#else ++ BUTT but[TV_E_NBUTTS], nopBut; ++#endif ++#ifdef TV_MULTILINGUAL ++/* int codeset; */ ++ struct coding_spec ccs; /* current coding_spec */ ++ BUTT csbut; ++ char *cv_text; ++ int cv_len; ++ struct context *ctx; ++ struct ml_text *txt; ++ struct csinfo_t *cs; ++#endif + } TVINFO; + + + static TVINFO tinfo[MAXTVWIN]; + static int hasBeenSized = 0; + static int haveWindows = 0; ++static int nbutts; /* # of buttons */ + static int mfwide, mfhigh, mfascent; /* size of chars in mono font */ + static int *event_retP, *event_doneP; /* used in tvChkEvent() */ +- ++#ifdef TV_MULTILINGUAL ++# define TV_PLAIN 0 ++# define TV_ISO_8859_1 1 ++# define TV_ISO_2022_JP 2 ++# define TV_EUC_JAPAN 3 ++# define TV_ISO_2022_INT_1 4 ++# define TV_ISO_2022_KR 5 ++# define TV_EUC_KOREA 6 ++# define TV_ISO_2022_SS2_8 7 ++# define TV_ISO_2022_SS2_7 8 ++# define TV_SHIFT_JIS 9 ++# define TV_NCSS 10 ++static char *codeSetNames[TV_NCSS] = { ++ "plain", ++ "iso-8859-1", ++ "iso-2022-jp", ++ "euc-japan", ++ "iso-2022-int-1", ++ "iso-2022-kr", ++ "euc-korea", ++ "iso-2022-ss2-8", ++ "iso-2022-ss2-7", ++ "Shift JIS", ++}; ++static struct coding_spec coding_spec[TV_NCSS] = { ++ /* --- G0 --- --- G1 --- --- G2 --- --- G3 --- GL GR EOL SF LS */ ++ /* plain */ ++ {{{{ 1,94,'B'}, { 1,94,'B'}, { 1,94,'B'}, { 1,94,'B'}}, 0, 0, 0, 1, 1}, ++ NULL}, ++ /* iso-8859-1 */ ++ {{{{ 1,94,'B'}, { 1,96,'A'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1, 0, 0, 0}, ++ NULL}, ++ /* iso-2022-jp */ ++ {{{{ 1,94,'B'}, {-1,94,'B'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 0, 0, 1, 0}, ++ NULL}, ++ /* euc-japan */ ++ {{{{ 1,94,'B'}, { 2,94,'B'}, { 1,94,'J'}, { 2,94,'D'}}, 0, 1, 0, 1, 0}, ++ NULL}, ++ /* iso-2022-int-1 */ ++ {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1, 0, 1, 1}, ++ NULL}, ++ /* iso-2022-kr */ ++ {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1, 0, 0, 1}, ++ NULL}, ++ /* euc-korea */ ++ {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1, 0, 0, 0}, ++ NULL}, ++ /* iso-2022-ss2-8 */ ++ {{{{ 1,94,'B'}, {-1,94,'C'}, { 0,94,'B'}, {-1,94,'B'}}, 0, 1, 0, 0, 0}, ++ NULL}, ++ /* iso-2022-ss2-7 */ ++ {{{{ 1,94,'B'}, {-1,94,'C'}, { 0,94,'B'}, {-1,94,'B'}}, 0, 1, 0, 1, 0}, ++ NULL}, ++ /* shift jis */ ++ {{{{ 1,94,'B'}, { 2,94,'B'}, { 1,94,'J'}, { 2,94,'D'}}, 0, 1, 1, 1, 0}, ++ sjis_to_jis}, ++}; ++#endif + + static void closeText PARM((TVINFO *)); + static int tvChkEvent PARM((TVINFO *, XEvent *)); +@@ -82,7 +176,15 @@ + static void textKey PARM((TVINFO *, int)); + static void doHexAsciiCmd PARM((TVINFO *, int)); + static void computeText PARM((TVINFO *)); +- ++#ifdef TV_L10N ++static int selectCodeset PARM((TVINFO *)); ++#endif ++#ifdef TV_MULTILINGUAL ++static void setCodingSpec PARM((TVINFO *, struct coding_spec *)); ++static void createCsWins PARM((char *)); ++static void openCsWin PARM((TVINFO *)); ++static void closeCsWin PARM((TVINFO *)); ++#endif + + /* HEXMODE output looks like this: + 0x00000000: 00 11 22 33 44 55 66 77 - 88 99 aa bb cc dd ee ff 0123456789abcdef +@@ -98,12 +200,51 @@ + XSizeHints hints; + XSetWindowAttributes xswa; + TVINFO *tv; ++#ifdef TV_MULTILINGUAL ++ int default_codeset; ++#endif + ++#ifdef TV_L10N ++ if (!xlocale) { ++#endif ++ mfwide = monofinfo->max_bounds.width; ++ mfhigh = monofinfo->ascent + monofinfo->descent; ++ mfascent = monofinfo->ascent; + +- mfwide = monofinfo->max_bounds.width; +- mfhigh = monofinfo->ascent + monofinfo->descent; +- mfascent = monofinfo->ascent; ++ nbutts = TV_E_NBUTTS; /* # of buttons */ ++#ifdef TV_L10N ++ } ++ else { ++ mfwide = monofsetinfo->max_logical_extent.width / 2; /* shit! */ ++ mfhigh = monofsetinfo->max_logical_extent.height + 1; ++ mfascent = mfhigh; ++ ++ nbutts = TV_J_NBUTTS; /* # of buttons */ ++ } ++#endif + ++#ifdef TV_MULTILINGUAL ++ { ++ char *dc = XGetDefault(theDisp, "xv", "codeSet"); ++ if (dc == NULL) ++ default_codeset = TV_DEFAULT_CODESET; ++ else { ++ for (i = 0; i < TV_NCSS; i++) { ++ if (strcmp(dc, codeSetNames[i]) == 0) ++ break; ++ } ++ if (i >= TV_NCSS) { ++ if (strcmp(dc, "iso-2022") == 0) ++ default_codeset = TV_PLAIN; ++ else { ++ SetISTR(ISTR_WARNING, "%s: unknown codeset.", dc); ++ default_codeset = TV_PLAIN; ++ } ++ } else ++ default_codeset = i; ++ } ++ } ++#endif + /* compute default size of textview windows. should be big enough to + hold an 80x24 text window */ + +@@ -118,6 +259,14 @@ + for (i=0; i<MAXTVWIN; i++) { + tv = &tinfo[i]; + ++#ifdef TV_MULTILINGUAL ++ tv->ctx = ml_create_context(ScreenOfDisplay(theDisp, theScreen)); ++ tv->txt = NULL; ++ tv->cv_text = NULL; ++ tv->cv_len = 0; ++ ml_set_charsets(tv->ctx, &coding_spec[TV_PLAIN].coding_system); ++#endif ++ + tv->win = CreateWindow((i<CMTWIN) ? "xv text viewer" : "xv image comments", + "XVtextview", + (i<CMTWIN) ? geom : cmtgeom, +@@ -162,24 +311,56 @@ + XSelectInput(theDisp, tv->textW, ExposureMask | ButtonPressMask); + + +- BTCreate(&(tv->but[TV_ASCII]), tv->win, 0,0,BUTTW,BUTTH, ++ BTCreate(&(tv->but[TV_ASCII]), tv->win, 0,0,BUTTW1,BUTTH, + "Ascii",infofg,infobg,hicol,locol); +- BTCreate(&(tv->but[TV_HEX]), tv->win, 0,0,BUTTW,BUTTH, ++ BTCreate(&(tv->but[TV_HEX]), tv->win, 0,0,BUTTW1,BUTTH, + "Hex",infofg,infobg,hicol,locol); +- BTCreate(&(tv->but[TV_CLOSE]), tv->win, 0,0,BUTTW,BUTTH, ++ BTCreate(&(tv->but[TV_CLOSE]), tv->win, 0,0,BUTTW1,BUTTH, + "Close",infofg,infobg,hicol,locol); + ++#ifdef TV_L10N ++ if (xlocale) { ++ BTCreate(&(tv->but[TV_RESCAN]), tv->win, 0,0,BUTTW2,BUTTH, ++ "RESCAN",infofg,infobg,hicol,locol); ++ BTCreate(&(tv->but[TV_USASCII]), tv->win, 0,0,BUTTW2,BUTTH, ++ "ASCII",infofg,infobg,hicol,locol); ++ BTCreate(&(tv->but[TV_JIS]), tv->win, 0,0,BUTTW2,BUTTH, ++ "JIS",infofg,infobg,hicol,locol); ++ BTCreate(&(tv->but[TV_EUCJ]), tv->win, 0,0,BUTTW2,BUTTH, ++ "EUC-j",infofg,infobg,hicol,locol); ++ BTCreate(&(tv->but[TV_MSCODE]), tv->win, 0,0,BUTTW2,BUTTH, ++ "MS Kanji",infofg,infobg,hicol,locol); ++ } ++#endif ++ + BTCreate(&(tv->nopBut), tv->win, 0,0, (u_int) tv->vscrl.tsize+1, + (u_int) tv->vscrl.tsize+1, "", infofg, infobg, hicol, locol); + tv->nopBut.active = 0; + + XMapSubwindows(theDisp, tv->win); + ++#ifdef TV_MULTILINGUAL ++ BTCreate(&tv->csbut, tv->win, 0, 0, BUTTW1, BUTTH, "Code Sets", ++ infofg, infobg, hicol, locol); ++#endif ++ + tv->text = (char *) NULL; + tv->textlen = 0; + tv->title[0] = '\0'; ++#ifdef TV_L10N ++ tv->code = (xlocale ? LOCALE_DEFAULT : 0); ++#endif ++#ifdef TV_MULTILINGUAL ++ tv->ccs = coding_spec[default_codeset]; ++#endif + } +- ++#ifdef TV_MULTILINGUAL ++ get_monofont_size(&mfwide, &mfhigh); ++ /* recalculate sizes. */ ++ defwide = 80 * mfwide + 2*LRMARGINS + 8 + 20; /* -ish */ ++ defhigh = 24 * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20; /* ish */ ++ cmthigh = 6 * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20; /* ish */ ++#endif + + for (i=0; i<MAXTVWIN; i++) { + resizeText(&tinfo[i], defwide, (i<CMTWIN) ? defhigh : cmthigh); +@@ -190,44 +371,54 @@ + + hasBeenSized = 1; /* we can now start looking at textview events */ + ++#ifdef TV_MULTILINGUAL ++ createCsWins("+100+100"); ++#endif + } + + + /***************************************************************/ +-void TextView(fname) ++int TextView(fname) + char *fname; + { + /* given a filename, attempts to read in the file and open a textview win */ + ++ int filetype; + long textlen; + char *text, buf[512], title[128], rfname[MAXPATHLEN+1]; + char *basefname[128]; /* just current fname, no path */ + FILE *fp; ++ char filename[MAXPATHLEN+1]; ++ ++ strncpy(filename, fname, sizeof(filename) - 1); ++#ifdef AUTO_EXPAND ++ Mkvdir(filename); ++ Dirtovd(filename); ++#endif + + basefname[0] = '\0'; +- strcpy(rfname, fname); ++ strncpy(rfname, filename, sizeof(rfname) - 1); + + /* see if this file is compressed. if it is, uncompress it, and view + the uncompressed version */ + +- if (ReadFileType(fname) == RFT_COMPRESS) { ++ filetype = ReadFileType(filename); ++ if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) { + #ifndef VMS +- if (!UncompressFile(fname, rfname)) return; /* failed to uncompress */ ++ if (!UncompressFile(filename, rfname, filetype)) return FALSE; + #else + /* chop off trailing '.Z' from friendly displayed basefname, if any */ +- strcpy (basefname, fname); ++ strncpy (basefname, filename, 128 - 1); + *rindex (basefname, '.') = '\0'; +- if (!UncompressFile(basefname, rfname)) return;/* failed to uncompress */ ++ if (!UncompressFile(basefname, rfname, filetype)) return FALSE; + #endif + } + +- +- + fp = fopen(rfname, "r"); + if (!fp) { + sprintf(buf,"Couldn't open '%s': %s", rfname, ERRSTR(errno)); + ErrPopUp(buf,"\nOh well"); +- return; ++ return FALSE; + } + + +@@ -239,16 +430,16 @@ + sprintf(buf, "File '%s' contains no data. (Zero length file.)", rfname); + ErrPopUp(buf, "\nOk"); + fclose(fp); +- return; ++ return FALSE; + } + +- text = (char *) malloc((size_t) textlen); ++ text = (char *) malloc((size_t) textlen + 1); + if (!text) { + sprintf(buf, "Couldn't malloc %ld bytes to read file '%s'", + textlen, rfname); + ErrPopUp(buf, "\nSo what!"); + fclose(fp); +- return; ++ return FALSE; + } + + if (fread(text, (size_t) 1, (size_t) textlen, fp) != textlen) { +@@ -256,6 +447,9 @@ + rfname); + ErrPopUp(buf, "\nHmm..."); + } ++#ifdef TV_MULTILINGUAL ++ text[textlen] = '\0'; ++#endif + + fclose(fp); + +@@ -263,6 +457,7 @@ + OpenTextView(text, (int) textlen, title, 1); + + /* note: text gets freed when window gets closed */ ++ return TRUE; + } + + +@@ -504,6 +699,10 @@ + tv->text = (char *) NULL; + tv->lines = (char **) NULL; + tv->numlines = tv->textlen = tv->hexmode = 0; ++ ++#ifdef TV_MULTILINGUAL ++ closeCsWin(tv); ++#endif + } + + +@@ -591,6 +790,40 @@ + else if (e->window == tv->textW) { } + else rv = 0; + } ++ else if (e->button == Button4) { /* note min vs. max, + vs. - */ ++ /* scroll regardless of where we are in the text window */ ++ if (e->window == tv->win || ++ e->window == tv->vscrl.win || ++ e->window == tv->hscrl.win || ++ e->window == tv->textW) ++ { ++ SCRL *sp=&(tv->vscrl); ++ int halfpage=sp->page/2; ++ ++ if (sp->val > sp->min+halfpage) ++ SCSetVal(sp,sp->val-halfpage); ++ else ++ SCSetVal(sp,sp->min); ++ } ++ else rv = 0; ++ } ++ else if (e->button == Button5) { /* note max vs. min, - vs. + */ ++ /* scroll regardless of where we are in the text window */ ++ if (e->window == tv->win || ++ e->window == tv->vscrl.win || ++ e->window == tv->hscrl.win || ++ e->window == tv->textW) ++ { ++ SCRL *sp=&(tv->vscrl); ++ int halfpage=sp->page/2; ++ ++ if (sp->val < sp->max-halfpage) ++ SCSetVal(sp,sp->val+halfpage); ++ else ++ SCSetVal(sp,sp->max); ++ } ++ else rv = 0; ++ } + else rv = 0; + } + +@@ -633,7 +866,9 @@ + int i, maxw, maxh; + XSizeHints hints; + ++#ifndef TV_MULTILINGUAL + if (tv->wide == w && tv->high == h) return; /* no change in size */ ++#endif + + if (XGetNormalHints(theDisp, tv->win, &hints)) { + hints.width = w; +@@ -657,10 +892,23 @@ + XMoveResizeWindow(theDisp, tv->textW, LRMARGINS, TOPMARGIN, + (u_int) tv->twWide, (u_int) tv->twHigh); + +- for (i=0; i<TV_NBUTTS; i++) { +- tv->but[i].x = tv->wide - (TV_NBUTTS-i) * (BUTTW+5); ++ for (i=0; i<TV_E_NBUTTS; i++) { ++ tv->but[i].x = tv->wide - (TV_E_NBUTTS-i) * (BUTTW1+5); + tv->but[i].y = tv->high - BUTTH - 5; + } ++#ifdef TV_MULTILINGUAL ++ tv->csbut.x = 5; ++ tv->csbut.y = tv->high - BUTTH - 5; ++#endif ++ ++#ifdef TV_L10N ++ if (xlocale) { ++ for (; i<TV_J_NBUTTS; i++) { ++ tv->but[i].x = 5 + (i-TV_E_NBUTTS) * (BUTTW2+5); ++ tv->but[i].y = tv->high - BUTTH - 5; ++ } ++ } ++#endif + + computeScrlVals(tv); + +@@ -711,6 +959,29 @@ + case TV_CLOSE: if (tv == &tinfo[CMTWIN]) CloseCommentText(); + else closeText(tv); + break; ++ ++#ifdef TV_L10N ++ case TV_RESCAN: ++ tv->code = selectCodeset(tv); ++ drawTextW(0, &tv->vscrl); ++ break; ++ case TV_USASCII: ++ tv->code = LOCALE_USASCII; ++ drawTextW(0, &tv->vscrl); ++ break; ++ case TV_JIS: ++ tv->code = LOCALE_JIS; ++ drawTextW(0, &tv->vscrl); ++ break; ++ case TV_EUCJ: ++ tv->code = LOCALE_EUCJ; ++ drawTextW(0, &tv->vscrl); ++ break; ++ case TV_MSCODE: ++ tv->code = LOCALE_MSCODE; ++ drawTextW(0, &tv->vscrl); ++ break; ++#endif /* TV_L10N */ + } + } + +@@ -745,8 +1016,10 @@ + drawNumLines(tv); + + /* draw the buttons */ +- for (i=0; i<TV_NBUTTS; i++) BTRedraw(&(tv->but[i])); +- ++ for (i=0; i<nbutts; i++) BTRedraw(&(tv->but[i])); ++#ifdef TV_MULTILINGUAL ++ BTRedraw(&tv->csbut); ++#endif + BTRedraw(&tv->nopBut); + } + +@@ -816,7 +1089,14 @@ + int delta; + SCRL *sptr; + { +- int i, j, lnum, hpos, cpos, extrach, lwide; ++ int i, j, lnum, hpos, vpos, cpos, lwide; ++#ifndef TV_MULTILINGUAL ++ int extrach; ++#endif ++#ifdef TV_L10N ++ int desig_stat; /* for ISO 2022-JP */ ++ /* 0: ASCII, 1: JIS X 0208, 2: GL is JIS X 0201 kana */ ++#endif + TVINFO *tv; + char linestr[512]; + u_char *sp, *ep, *lp; +@@ -839,12 +1119,38 @@ + XSetFont(theDisp, theGC, monofont); + + hpos = tv->hscrl.val; ++ vpos = tv->vscrl.val; + lwide = (tv->chwide < 500) ? tv->chwide : 500; + + /* draw text */ + if (!tv->hexmode) { /* ASCII mode */ ++#ifdef TV_MULTILINGUAL ++ XClearArea(theDisp, tv->textW, 0, 0, ++ (u_int) tv->twWide, (u_int) tv->twHigh, False); ++ if(tv->txt == NULL) ++ return; ++ else { ++ int i; ++ int y; ++ struct ml_text *tp = tv->txt; ++ struct ml_line *lp; ++ ++ XSetFunction(theDisp, theGC, GXcopy); ++ XSetClipMask(theDisp, theGC, None); ++ y = 3; ++ for (lp = &tp->lines[vpos], i = tp->nlines - vpos; ++ i > 0; lp++, i--) { ++ XDrawText16(theDisp, tv->textW, theGC, ++ -mfwide * hpos + 3, y + lp->ascent, ++ lp->items, lp->nitems); ++ y += lp->ascent + lp->descent; ++ if (y > tv->twHigh) ++ break; ++ } ++ } ++#else + for (i=0; i<tv->chhigh; i++) { /* draw each line */ +- lnum = i + tv->vscrl.val; ++ lnum = i + vpos; + if (lnum < tv->numlines-1) { + + /* find start of displayed portion of line. This is *wildly* +@@ -865,7 +1171,13 @@ + cpos--; sp++; + } + else if (*sp < 32) extrach = 1; ++ ++#ifdef TV_L10N ++ else if (!tv->code && *sp > 127) extrach = 3; ++#else + else if (*sp > 127) extrach = 3; ++#endif ++ + else sp++; + } + else { +@@ -881,6 +1193,10 @@ + + /* build up the linestr buffer, which is the current line, padded + with blanks to a width of exactly tv->chwide chars */ ++#ifdef TV_L10N ++ desig_stat = 0; /* for ISO 2022-JP */ ++ /* 0: ASCII, 1: JIS X 0208, 2: GL is JIS X 0201 kana */ ++#endif + for (cpos=0, lp=(byte *) linestr; cpos<lwide; cpos++, lp++) { + if (sp>=ep) *lp = ' '; + else { +@@ -894,13 +1210,117 @@ + cpos--; lp--; sp++; + } + ++#ifdef TV_L10N ++ else if (*sp < 32 && !(tv->code == LOCALE_JIS && *sp == 0x1b)) { ++#else + else if (*sp < 32) { ++#endif + if (!extrach) extrach = 2; + if (extrach == 2) *lp = '^'; + else if (extrach == 1) *lp = *sp + 64; + } + ++#ifdef TV_L10N ++ /* convert to EUC-Japan */ ++ else if (tv->code == LOCALE_JIS) { ++ if (*sp == 0x1b) { /* ESC */ ++ if (*(sp+1) == '$') { ++ if (*(sp+2) == 'B' || *(sp+2) == 'A' || *(sp+2) == '@') { ++ /* ESC $ B, ESC $ A, ESC $ @ */ ++ desig_stat = 1; ++ sp += 3; cpos--; lp--; ++ } ++ else if (*(sp+2) == '(' && *(sp+3) == 'B') { ++ /* ESC $ ( B */ ++ desig_stat = 1; ++ sp += 4; cpos--; lp--; ++ } ++ } ++ else if (*(sp+1) == '(') { ++ if (*(sp+2) == 'B' || *(sp+2) == 'J' || *(sp+2) == 'H') { ++ /* ESC ( B, ESC ( J, ESC ( H */ ++ desig_stat = 0; ++ sp += 3; cpos--; lp--; ++ } ++ else if (*(sp+2) == 'I') { ++ /* ESC ( I */ ++ desig_stat = 2; ++ sp += 3; cpos--; lp--; ++ } ++ } ++ else if (*(sp+1) == ')' && *(sp+2) == 'I') { ++ /* ESC ) I */ ++ desig_stat = 2; ++ sp += 3; cpos--; lp--; ++ } ++ else { /* error */ ++ *lp = ' '; sp++; ++ } ++ } ++ ++ else { ++ switch (desig_stat) { ++ case 0: /* ASCII */ ++ *lp = *sp++; ++ break; ++ case 1: /* JIS X 0208 */ ++ *lp++ = *sp++ | 0x80; ++ *lp = *sp++ | 0x80; ++ cpos++; ++ break; ++ case 2: /* JIS X 0201 kana */ ++#if defined(__osf__) && !defined(X_LOCALE) ++ *lp = '='; sp++; ++#else ++ *lp++ = 0x8e; /* ^N | 0x80 */ ++ *lp = *sp++ | 0x80; ++#endif ++ break; ++ default: /* error */ ++ *lp = *sp++; ++ break; ++ } ++ } ++ } ++ ++ else if (tv->code == LOCALE_MSCODE) { ++ if ((*sp >= 0x81 && *sp <= 0x9f) ++ || (*sp >= 0xe0 && *sp <= 0xef)) { ++ static u_char c1, c2; ++ ++/*fprintf(stderr, "(%x,%x)->", *sp, *(sp+1));*/ ++ c1 = ((*sp - ((*sp>=0xe0) ? 0xb0 : 0x70)) << 1) ++ - ((*(sp+1)<=0x9e) ? 1 : 0); ++ c2 = *(sp+1); ++ if (c2 >= 0x9f) c2 -= 0x7e; /* 0x9F - 0xFC */ ++ else if (c2 >= 0x80) c2 -= 0x20; /* 0x80 - 0x9E */ ++ else c2 -= 0x1f; /* 0x40 - 0x7E */ ++ ++ *lp++ = c1 | 0x80; ++ *lp = c2 | 0x80; ++ sp += 2; ++/*fprintf(stderr, "(%x %x) ", c1 | 0x80, c2 | 0x80);*/ ++ cpos++; ++ } ++ ++ else if (*sp >= 0xa1 && *sp <= 0xdf) { /* JIS X 0201 kana */ ++#if defined(__osf__) && !defined(X_LOCALE) ++ *lp = '='; sp++; ++#else ++ *lp++ = 0x8e; /* ^N | 0x80 */ ++ *lp = *sp++; ++#endif ++ } ++ ++ else *lp = *sp++; ++ } ++#endif /* TV_L10N */ ++ ++#ifdef TV_L10N ++ else if (!tv->code && *sp > 127) { ++#else + else if (*sp > 127) { ++#endif + if (!extrach) extrach = 4; + if (extrach == 4) *lp = '\\'; + else if (extrach == 3) *lp = ((u_char)(*sp & 0700) >> 6) + '0'; +@@ -916,6 +1336,9 @@ + } + } + } ++#ifdef TV_L10N ++ *lp = '\0'; /* terminate linestr */ ++#endif + } + + else { /* below bottom of file. Just build a blank str */ +@@ -923,15 +1346,22 @@ + } + + /* draw the line */ +- XDrawImageString(theDisp, tv->textW, theGC, +- 3, i*mfhigh + 3 + mfascent, linestr, lwide); ++#ifdef TV_L10N ++ if (xlocale) ++ XmbDrawImageString(theDisp, tv->textW, monofset, theGC, ++ 3, i*mfhigh + 1 + mfascent, linestr, strlen(linestr)); ++ else ++#endif ++ XDrawImageString(theDisp, tv->textW, theGC, ++ 3, i*mfhigh + 3 + mfascent, linestr, lwide); + } /* for i ... */ ++#endif /* TV_MULTILINGUAL */ + } /* if hexmode */ + + + else { /* HEX MODE */ + for (i=0; i<tv->chhigh; i++) { /* draw each line */ +- lnum = i + tv->vscrl.val; ++ lnum = i + vpos; + if (lnum < tv->hexlines) { + + char hexstr[80], tmpstr[16]; +@@ -957,7 +1387,11 @@ + + for (j=0; j<16; j++) { + if (sp+j < ep) { ++#ifdef TV_L10N ++ if (sp[j] >= 32 && (sp[j] <= 127 || tv->code)) *lp++ = sp[j]; ++#else + if (sp[j] >= 32 && sp[j] <= 127) *lp++ = sp[j]; ++#endif + else *lp++ = '.'; + } + else *lp++ = ' '; +@@ -1005,14 +1439,21 @@ + int i; + BUTT *bp; + +- for (i=0, bp=tv->but; i<TV_NBUTTS; i++, bp++) { ++ for (i=0, bp=tv->but; i<nbutts; i++, bp++) { + if (PTINRECT(x,y,bp->x,bp->y,bp->w,bp->h)) break; + } + +- if (i<TV_NBUTTS) { ++ if (i<nbutts) { + if (BTTrack(bp)) doCmd(tv, i); + return; + } ++ ++#ifdef TV_MULTILINGUAL ++ if (PTINRECT(x, y, tv->csbut.x, tv->csbut.y, tv->csbut.w, tv->csbut.h)) { ++ if (BTTrack(&tv->csbut)) ++ openCsWin(tv); ++ } ++#endif + } + + +@@ -1042,13 +1483,38 @@ + + /* keyboard equivalents */ + switch (buf[0]) { +- case '\001': doCmd(tv, TV_ASCII); break; /* ^A = Ascii */ +- case '\010': doCmd(tv, TV_HEX); break; /* ^H = Hex */ +- +- case '\033': doCmd(tv, TV_CLOSE); break; /* ESC = Close window */ ++ case '\001': case 'a': case 'A': ++ doCmd(tv, TV_ASCII); break; /* ^A = Ascii */ ++ case '\010': case 'h': case 'H': ++ doCmd(tv, TV_HEX); break; /* ^H = Hex */ ++ ++ case '\021': case 'q': case 'Q': ++ case '\003': case 'c': case 'C': ++ case '\033': ++ doCmd(tv, TV_CLOSE); break; /* ESC = Close window */ + + default: break; + } ++ ++#ifdef TV_L10N ++ if (xlocale) { ++ switch (buf[0]) { ++ case '\022': case 'r': case 'R': ++ doCmd(tv, TV_RESCAN); break; ++ case '\012': case 'j': case 'J': ++ doCmd(tv, TV_JIS); break; ++ case '\005': case 'e': case 'E': ++ case '\025': case 'u': case 'U': ++ doCmd(tv, TV_EUCJ); break; ++ case '\015': case 'm': case 'M': ++ case '\023': case 's': case 'S': ++ doCmd(tv, TV_MSCODE); break; ++ ++ default: break; ++ } ++ } ++#endif /* TV_L10N */ ++ + } + + +@@ -1109,7 +1575,20 @@ + if (i<tv->numlines-1) SCSetVal(&tv->vscrl, i); + } + ++#ifdef TV_L10N ++ /* redraw text */ ++ if (xlocale) { ++ XClearArea(theDisp, tv->textW, 0, 0, ++ (u_int) tv->twWide, (u_int) tv->twHigh, False); ++ ++ drawTextW(0, &tv->vscrl); ++ } ++#endif ++#ifdef TV_MULTILINGUAL ++ XClearArea(theDisp, tv->textW, 0, 0, ++ (u_int) tv->twWide, (u_int) tv->twHigh, False); + drawTextW(0, &tv->vscrl); ++#endif + } + + +@@ -1122,9 +1601,22 @@ + int i,j,wide,maxwide,space; + byte *sp; + ++#ifdef TV_L10N ++ /* select code-set */ ++ if (xlocale) ++ tv->code = selectCodeset(tv); ++#endif /* TV_L10N */ ++ + if (!tv->text) { + tv->numlines = tv->hexlines = 0; + tv->lines = (char **) NULL; ++#ifdef TV_MULTILINGUAL ++ if (tv->cv_text != NULL) { ++ free(tv->cv_text); ++ tv->cv_text = NULL; ++ } ++ tv->txt = NULL; ++#endif + return; + } + +@@ -1172,17 +1664,129 @@ + wide += space; + } + else if (*sp < 32) wide += 2; ++#ifdef TV_L10N ++ else if (*sp > 127 && !tv->code) wide += 4; ++#else + else if (*sp > 127) wide += 4; ++#endif + else wide++; + } + if (wide > maxwide) maxwide = wide; + } + tv->maxwide = maxwide; + ++#ifdef TV_MULTILINGUAL ++ ml_set_charsets(tv->ctx, &tv->ccs.coding_system); ++ if (tv->cv_text != NULL) { ++ free(tv->cv_text); ++ tv->cv_text = NULL; ++ } ++ if (tv->ccs.converter == NULL) { ++ tv->txt = ml_draw_text(tv->ctx, tv->text, tv->textlen); ++ } else { ++ tv->cv_text = (*tv->ccs.converter)(tv->text, tv->textlen, &tv->cv_len); ++ tv->txt = ml_draw_text(tv->ctx, tv->cv_text, tv->cv_len); ++ } ++ tv->maxwide = tv->txt->width / mfwide; ++ tv->numlines = tv->txt->height / mfhigh + 1; ++#endif ++ + tv->hexlines = (tv->textlen + 15) / 16; + } + + ++/***************************************************/ ++#ifdef TV_L10N ++static int selectCodeset(tv) ++ TVINFO *tv; ++{ ++ u_char *sp; ++ int i, len; ++ int code = LOCALE_USASCII; /* == 0 */ ++ ++ ++ len = tv->textlen; ++ ++ /* select code-set */ ++ if (xlocale) { ++ sp = (u_char *) tv->text; i = 0; ++ while (i < len - 1) { ++ if (*sp == 0x1b && ++ (*(sp+1) == '$' || *(sp+1) == '(' || *(sp+1) == ')')) { ++ code = LOCALE_JIS; ++ break; ++ } ++ ++ else if (*sp >= 0xa1 && *sp <= 0xdf) { ++ if (*(sp+1) >= 0xf0 && *(sp+1) <= 0xfe) { ++ code = LOCALE_EUCJ; ++ break; ++ } ++# if (LOCALE_DEFAULT == LOCALE_EUCJ) ++ else { ++ sp++; i++; ++ } ++# endif ++ } ++ ++ else if ((*sp >= 0x81 && *sp <= 0x9f) || (*sp >= 0xe0 && *sp <= 0xef)) { ++ if ((*(sp+1) >= 0x40 && *(sp+1) <= 0x7e) || *(sp+1) == 0x80) { ++ code = LOCALE_MSCODE; ++ break; ++ } ++ else if (*(sp+1) == 0xfd || *(sp+1) == 0xfe) { ++ code = LOCALE_EUCJ; ++ break; ++ } ++ else { ++ sp++; i++; ++ } ++ } ++ ++ else if (*sp >= 0xf0 && *sp <= 0xfe) { ++ code = LOCALE_EUCJ; ++ break; ++ } ++ ++ sp++; i++; ++ } ++ if (!code) code = LOCALE_DEFAULT; ++ } ++ ++ return code; ++} ++#endif /* TV_L10N */ ++ ++#ifdef TV_MULTILINGUAL ++static void setCodingSpec(tv, cs) ++ TVINFO *tv; ++ struct coding_spec *cs; ++{ ++ if (xvbcmp((char *) &tv->ccs, (char *) cs, sizeof *cs) == 0) ++ return; ++ ++ tv->ccs = *cs; ++#if 0 ++ ml_set_charsets(tv->ctx, &tv->ccs.coding_system); ++ if (tv->cv_text != NULL) { ++ free(tv->cv_text); ++ tv->cv_text = NULL; ++ } ++ if (tv->ccs.converter == NULL) { ++ tv->txt = ml_draw_text(tv->ctx, tv->text, tv->textlen); ++ } else { ++ tv->cv_text = (*tv->ccs.converter)(tv->text, tv->textlen, &tv->cv_len); ++ tv->txt = ml_draw_text(tv->ctx, tv->cv_text, tv->cv_len); ++ } ++#else ++ computeText(tv); ++ computeScrlVals(tv); ++#endif ++ /* drawTextW(0, &tv->vscrl); */ ++} ++#endif ++ ++ + /**********************************************************************/ + /* BUILT-IN TEXT FILES ************************************************/ + /**********************************************************************/ +@@ -1555,8 +2159,509 @@ + OpenTextView(keyhelp, (int) strlen(keyhelp), "XV Help", 0); + } + ++#ifdef TV_MULTILINGUAL ++ ++#define TV_ML_ACCEPT TV_NCSS ++#define TV_ML_CLOSE (TV_ML_ACCEPT + 1) ++#define TV_ML_NBUTTS (TV_ML_CLOSE + 1) ++ ++#define TV_ML_RETCODE 0 ++# define TV_ML_RET_LF 0 ++# define TV_ML_RET_CRLF 1 ++# define TV_ML_RET_CR 2 ++# define TV_ML_RET_ANY 3 ++#define TV_ML_GL 1 ++#define TV_ML_GR 2 ++#define TV_ML_CVTR 3 ++#define TV_ML_NRBUTTS 4 ++ ++#define TV_ML_SHORT 0 ++#define TV_ML_LOCK 1 ++#define TV_ML_NCBUTTS 2 ++ ++#define TV_ML_NLISTS 4 ++ ++#define CSWIDE (BUTTW3 * 5 + 5 * 6) ++#define CSHIGH 450 ++ ++typedef struct csinfo_t { ++ TVINFO *tv; ++ RBUTT *rbt[TV_ML_NRBUTTS]; ++ CBUTT cbt[TV_ML_NCBUTTS]; ++ LIST ls[TV_ML_NLISTS]; ++ BUTT bt[TV_ML_NBUTTS]; ++ int up; ++ Window win; ++ struct coding_spec tcs; /* temporary coding_spec */ ++} CSINFO; ++CSINFO csinfo[MAXTVWIN]; ++static char **regs; ++static int nregs; ++ ++static int csCheckEvent PARM((CSINFO *, XEvent *)); ++static void csReflect PARM((CSINFO *)); ++static void csRedraw PARM((CSINFO *)); ++static void csListRedraw PARM((LIST *)); ++static void csLsRedraw PARM((int, SCRL *)); ++static void create_registry_list PARM((void)); ++ ++static char *(*cvtrtab[])PARM((char *, int, int *)) = { ++ NULL, ++ sjis_to_jis, ++}; ++ ++static void createCsWins(geom) ++ char *geom; ++{ ++ XSetWindowAttributes xswa; ++ int i, j; ++ ++ create_registry_list(); ++ ++ xswa.backing_store = WhenMapped; ++ for (i = 0; i < MAXTVWIN; i++) { ++ char nam[8]; ++ TVINFO *tv = &tinfo[i]; ++ CSINFO *cs = &csinfo[i]; ++ tv->cs = cs; ++ cs->tv = tv; ++ sprintf(nam, "XVcs%d", i); ++ cs->win = CreateWindow("xv codeset", nam, geom, ++ CSWIDE, CSHIGH, infofg, infobg, 0); ++ if (!cs->win) FatalError("couldn't create 'charset' window!"); ++#ifdef BACKING_STORE ++ XChangeWindowAttributes(theDisp, cs->win, CWBackingStore, &xswa); ++#endif ++ XSelectInput(theDisp, cs->win, ExposureMask | ButtonPressMask); ++ ++ DrawString(cs->win, 5, 5 + ASCENT, "Initial States"); ++ for (i = 0; i < TV_ML_NLISTS; i++) { ++ int x, y; ++ char buf[80]; ++ ++ if (i / 2 == 0) ++ x = 15; ++ else ++ x = 280; ++ if (i % 2 == 0) ++ y = 5 + LINEHIGH * 1; ++ else ++ y = 5 + LINEHIGH * 7 + SPACING * 3; ++ ++ sprintf(buf, "Designation for G%d:", i + 1); ++ DrawString(cs->win, x, y + ASCENT, buf); ++ ++ LSCreate(&cs->ls[i], cs->win, x + 15, y + LINEHIGH, ++ 200, LINEHIGH * 5, 5, ++ regs, nregs + 2, ++ infofg, infobg, hicol, locol, csLsRedraw, 0, 0); ++ cs->ls[i].selected = 0; ++ } ++ ++ for (i = 0; i < 2; i++) { ++ char *p; ++ int n; ++ int x, y; ++ ++ if ((p = (char *) malloc(3 * 4)) == NULL) ++ FatalError("out of memory in createCsWins()."); ++ strcpy(p, "G1 G2 G3 G4"); ++ p[2] = p[5] = p[8] = '\0'; ++ n = (i == 0 ? TV_ML_GL : TV_ML_GR); ++ x = (i == 0 ? 15 : 280); ++ y = 235; ++ DrawString(cs->win, x, y + ASCENT, "Assignment for GL:"); ++ x += 15; ++ y += LINEHIGH; ++ cs->rbt[n] = RBCreate(NULL, cs->win, ++ x, y, p, infofg, infobg, hicol, locol); ++ for (j = 1; j < 4; j++) { ++ p += 3; ++ x += 50; ++ RBCreate(cs->rbt[n], cs->win, ++ x, y, p, infofg, infobg, hicol, locol); ++ } ++ } ++ ++ DrawString(cs->win, 5, 280 + ASCENT, "Ret Code:"); ++ cs->rbt[TV_ML_RETCODE] = ++ RBCreate(NULL, cs->win, 20, 300, "LF", infofg,infobg, hicol,locol); ++ RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 20, 300 + 20, "CR+LF", ++ infofg, infobg, hicol, locol); ++ RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 90, 300, "CR", ++ infofg, infobg, hicol, locol); ++ RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 90, 300 + 20, "Any", ++ infofg, infobg, hicol, locol); ++ ++ DrawString(cs->win, 350, 280 + ASCENT, "Converter:"); ++ cs->rbt[TV_ML_CVTR] = ++ RBCreate(NULL, cs->win, 365, 300, "Nothing", ++ infofg, infobg, hicol, locol); ++ RBCreate(cs->rbt[TV_ML_CVTR], cs->win, 365, 300 + 20, "Shift JIS", ++ infofg, infobg, hicol, locol); ++ ++ CBCreate(&cs->cbt[TV_ML_SHORT], cs->win, 200, 300, "Short Form", ++ infofg, infobg, hicol, locol); ++ CBCreate(&cs->cbt[TV_ML_LOCK], cs->win, 200, 320, "Locking Shift", ++ infofg, infobg, hicol, locol); ++ ++ for (j = 0; j < TV_NCSS; j++) { ++ BTCreate(&cs->bt[j], cs->win, ++ 5 + (BUTTW3 + 5) * (j % 5), ++ 350 + 5 + (BUTTH + 5) * (j / 5), ++ BUTTW3, BUTTH, codeSetNames[j], ++ infofg, infobg, hicol, locol); ++ } ++ BTCreate(&cs->bt[TV_ML_ACCEPT], cs->win, ++ CSWIDE - 10 - BUTTW3 * 2, CSHIGH - 5 - BUTTH, BUTTW3, BUTTH, ++ "Accept", infofg, infobg, hicol, locol); ++ BTCreate(&cs->bt[TV_ML_CLOSE], cs->win, ++ CSWIDE - 5 - BUTTW3, CSHIGH - 5 - BUTTH, BUTTW3, BUTTH, ++ "Close", infofg, infobg, hicol, locol); + ++ XMapSubwindows(theDisp, cs->win); ++ cs->up = 0; ++ } ++} + ++static void openCsWin(tv) ++ TVINFO *tv; ++{ ++ CSINFO *cs = tv->cs; ++ if (cs->up) ++ return; + ++ XMapRaised(theDisp, cs->win); ++ cs->up = 1; ++ cs->tcs = cs->tv->ccs; ++ csReflect(cs); ++} + ++static void closeCsWin(tv) ++ TVINFO *tv; ++{ ++ CSINFO *cs = tv->cs; ++ if (!cs->up) ++ return; ++ cs->up = 0; ++ XUnmapWindow(theDisp, cs->win); ++} ++ ++int CharsetCheckEvent(xev) ++ XEvent *xev; ++{ ++ int i; ++ CSINFO *cs; ++ ++ for (cs = csinfo, i = 0; i < MAXTVWIN; cs++, i++) { ++ if (!cs->up) ++ continue; ++ if (csCheckEvent(cs, xev)) ++ break; ++ } ++ if (i < MAXTVWIN) ++ return 1; ++ return 0; ++} ++ ++static int csCheckEvent(cs, xev) ++ CSINFO *cs; ++ XEvent *xev; ++{ ++ RBUTT **rbp; ++ CBUTT *cbp; ++ LIST *ls; ++ BUTT *bp; ++ int i, n; ++ ++ if (xev->type == Expose) { ++ int x, y, w, h; ++ XExposeEvent *e = (XExposeEvent *) xev; ++ x = e->x; y = e->y; w = e->width; h = e->height; ++ ++ if (cs->win == e->window){ ++ csRedraw(cs); ++ return 1; ++ } else { ++ for (i = 0; i < TV_ML_NLISTS; i++) { ++ if (cs->ls[i].win == e->window) { ++ LSRedraw(&cs->ls[i], 0); ++ return 1; ++ } ++ } ++ for (i = 0; i < TV_ML_NLISTS; i++) { ++ if (cs->ls[i].scrl.win == e->window) { ++ SCRedraw(&cs->ls[i].scrl); ++ return 1; ++ } ++ } ++ } ++ } else if (xev->type == ButtonPress) { ++ int x, y; ++ XButtonEvent *e = (XButtonEvent *) xev; ++ x = e->x; y = e->y; ++ if (cs->win == e->window) { ++ for (bp = cs->bt, i = 0; i < TV_ML_NBUTTS; bp++, i++) { ++ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) ++ break; ++ } ++ if (i < TV_ML_NBUTTS) { ++ if (BTTrack(bp)) { ++ if (i < TV_NCSS) { ++ cs->tcs = coding_spec[i]; ++ csReflect(cs); ++ } else { ++ switch (i) { ++ case TV_ML_ACCEPT: ++ setCodingSpec(cs->tv, &cs->tcs); ++ break; ++ case TV_ML_CLOSE: ++ closeCsWin(cs->tv); ++ break; ++ } ++ } ++ } ++ return 1; ++ } ++ for (cbp = cs->cbt, i = 0; i < TV_ML_NCBUTTS; cbp++, i++) { ++ if (CBClick(cbp, x, y) && CBTrack(cbp)) ++ break; ++ } ++ if (i < TV_ML_NCBUTTS) { ++ switch (i) { ++ case TV_ML_SHORT: ++ cs->tcs.coding_system.short_form = cbp->val; ++ break; ++ case TV_ML_LOCK: ++ cs->tcs.coding_system.lock_shift = cbp->val; ++ break; ++ } ++ return 1; ++ } ++ for (rbp = cs->rbt, i = 0; i < TV_ML_NRBUTTS; rbp++, i++) { ++ if ((n = RBClick(*rbp, x, y)) >= 0 && RBTrack(*rbp, n)) { ++ break; ++ } ++ } ++ if (i < TV_ML_NRBUTTS) { ++ switch (i) { ++ case TV_ML_RETCODE: ++ cs->tcs.coding_system.eol = n; ++ break; ++ case TV_ML_GL: ++ cs->tcs.coding_system.gl = n; ++ break; ++ case TV_ML_GR: ++ cs->tcs.coding_system.gr = n; ++ break; ++ case TV_ML_CVTR: ++ cs->tcs.converter = cvtrtab[n]; ++ break; ++ } ++ return 1; ++ } ++ } else { ++ for (ls = cs->ls, i = 0; i < TV_ML_NLISTS; ls++, i++) { ++ if (ls->win == e->window) { ++ LSClick(ls, e); ++ n = ls->selected; ++ if (n < nregs) { ++ char r[32], *p = r; ++ int b7; ++ strcpy(r, regs[n]); ++ if ((p = strrchr(r, '/')) != NULL) { ++ *p = '\0'; ++ b7 = (*(p + 1) == 'R' ? 1 : 0); ++ } else ++ b7 = 0; /* shouldn't occur */ ++ cs->tcs.coding_system.design[i] = lookup_design(r, b7); ++ } else if (n == nregs) /* initially none is designed. */ ++ cs->tcs.coding_system.design[i].bpc = 0; ++ else ++ cs->tcs.coding_system.design[i].bpc = -1; ++ return 1; ++ } ++ } ++ for (ls = cs->ls, i = 0; i < TV_ML_NLISTS; ls++, i++) { ++ if (ls->scrl.win == e->window) { ++ SCTrack(&ls->scrl, x, y); ++ return 1; ++ } ++ } ++ } ++ } ++ return 0; ++} ++ ++static void csReflect(cs) ++ CSINFO *cs; ++{ ++ int i; ++ ++ RBSelect(cs->rbt[TV_ML_RETCODE], cs->tcs.coding_system.eol); ++ RBSelect(cs->rbt[TV_ML_GL], cs->tcs.coding_system.gl); ++ RBSelect(cs->rbt[TV_ML_GR], cs->tcs.coding_system.gr); ++ for (i = 0; i < sizeof cvtrtab / sizeof cvtrtab[0]; i++) { ++ if (cs->tcs.converter == cvtrtab[i]) ++ break; ++ } ++ if (i >= sizeof cvtrtab / sizeof cvtrtab[0]) ++ FatalError("program error in csReflect()."); ++ RBSelect(cs->rbt[TV_ML_CVTR], i); ++ ++ cs->cbt[TV_ML_SHORT].val = cs->tcs.coding_system.short_form; ++ cs->cbt[TV_ML_LOCK].val = cs->tcs.coding_system.lock_shift; ++ for (i = 0; i < TV_ML_NLISTS; i++) { ++ struct design design = cs->tcs.coding_system.design[i]; ++ char *reg, r[32]; ++ int b7; ++ int n = 0; ++ switch (design.bpc) { ++ case -1: ++ n = nregs + 1; ++ break; ++ case 0: ++ n = nregs; ++ break; ++ case 1: ++ case 2: ++ if ((reg = lookup_registry(design, &b7)) == NULL) ++ FatalError("internal error in csReflect."); ++ sprintf(r, "%s/%s", reg, b7 ? "Right" : "Left"); ++ for (n = 0; n < nregs; n++) { ++ if (strcmp(regs[n], r) == 0) ++ break; ++ } ++ } ++ cs->ls[i].selected = n; ++ ScrollToCurrent(&cs->ls[i]); ++ } ++ csRedraw(cs); ++ for (i = 0; i < TV_ML_NLISTS; i++) ++ csListRedraw(&cs->ls[i]); ++} ++ ++static void csRedraw(cs) ++ CSINFO *cs; ++{ ++ int i; ++ ++ XSetForeground(theDisp, theGC, infofg); ++ DrawString(cs->win, 5,5 + ASCENT, "Initial States"); ++ for (i = 0; i < TV_ML_NLISTS; i++) { ++ int x, y; ++ char buf[80]; ++ ++ if (i / 2 == 0) ++ x = 15; ++ else ++ x = 280; ++ if (i % 2 == 0) ++ y = 5 + LINEHIGH * 1; ++ else ++ y = 5 + LINEHIGH * 7 + SPACING * 3; ++ ++ sprintf(buf, "Designation for G%d:", i); ++ DrawString(cs->win, x, y + ASCENT, buf); ++ } ++ ++ DrawString(cs->win, 15, 235 + ASCENT, "Invocation for GL:"); ++ DrawString(cs->win, 280, 235 + ASCENT, "Invocation for GR:"); ++ DrawString(cs->win, 5, 280 + ASCENT, "Ret Code:"); ++ DrawString(cs->win, 350, 280 + ASCENT, "Converter:"); ++ ++ for (i = 0; i < TV_ML_NBUTTS; i++) ++ BTRedraw(&cs->bt[i]); ++ for (i = 0; i < TV_ML_NCBUTTS; i++) ++ CBRedraw(&cs->cbt[i]); ++ for (i = 0; i < TV_ML_NRBUTTS; i++) ++ RBRedraw(cs->rbt[i], -1); ++} ++ ++static void csListRedraw(ls) ++ LIST *ls; ++{ ++ int i; ++ for (i = 0; i < TV_ML_NLISTS; i++) { ++ LSRedraw(ls, 0); ++ SCRedraw(&ls->scrl); ++ } ++} ++ ++static void csLsRedraw(delta, sptr) ++ int delta; ++ SCRL *sptr; ++{ ++ int i, j; ++ for (i = 0; i < MAXTVWIN; i++) { ++ for (j = 0; j < TV_ML_NLISTS; j++) { ++ if (sptr == &csinfo[i].ls[j].scrl) { ++ LSRedraw(&csinfo[i].ls[j], delta); ++ return; ++ } ++ } ++ } ++} ++ ++int CharsetDelWin(win) ++ Window win; ++{ ++ CSINFO *cs; ++ int i; ++ ++ for (cs = csinfo, i = 0; i < TV_NCSS; cs++, i++) { ++ if (cs->win == win) { ++ if (cs->up) { ++ XUnmapWindow(theDisp, cs->win); ++ cs->up = 0; ++ } ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static int reg_comp PARM((const void *, const void *)); ++static void create_registry_list() ++{ ++ struct design d; ++ char *names, *p; ++ int i; ++ ++ if ((p = names = (char *) malloc(32 * 0x80 * 2 * 2)) == NULL) ++ FatalError("out of memory in create_name_list#1."); ++ nregs = 0; ++ for (d.bpc = 1; d.bpc <=2; d.bpc++) { ++ for (d.noc = 94; d.noc <= 96; d.noc += 2) { ++ for (d.des = ' '; (unsigned char) d.des < 0x80; d.des++) { ++ int b7; ++ char *r; ++ if ((r = lookup_registry(d, &b7)) != NULL) { ++ sprintf(p, "%s/%s", r, b7 ? "Right" : "Left"); ++ p += strlen(p) + 1; ++ nregs++; ++ } ++ } ++ } ++ } ++ if ((names = (char *) realloc(names, (size_t) (p - names))) == NULL) ++ FatalError("out of memory in create_name_list#2."); ++ if ((regs = (char **) malloc(sizeof(char *) * (nregs + 3))) == NULL) ++ FatalError("out of memory in create_name_list#3."); ++ p = names; ++ for (i = 0; i < nregs; i++) { ++ regs[i] = p; ++ p += strlen(p) + 1; ++ } ++ qsort(regs, (size_t) nregs, sizeof(char *), reg_comp); ++ regs[i++] = "nothing"; ++ regs[i++] = "unused"; ++ regs[i++] = NULL; ++} ++static int reg_comp(dst, src) ++ const void *dst, *src; ++{ ++ return strcmp(*(char **) dst, *(char **) src); ++} + ++#endif /* TV_MULTILINGUAL */ +diff -ruN xv-3.10a-bugfixes/xvtiff.c xv-3.10a-enhancements/xvtiff.c +--- xv-3.10a-bugfixes/xvtiff.c 2005-03-27 17:25:31.000000000 -0800 ++++ xv-3.10a-enhancements/xvtiff.c 2005-04-17 14:11:55.000000000 -0700 +@@ -512,7 +512,7 @@ + vsprintf(cp, fmt, ap); + strcat(cp, "."); + +- SetISTR(ISTR_WARNING,buf); ++ SetISTR(ISTR_WARNING, "%s", buf); + + error_occurred = 1; + } +@@ -536,7 +536,7 @@ + vsprintf(cp, fmt, ap); + strcat(cp, "."); + +- SetISTR(ISTR_WARNING,buf); ++ SetISTR(ISTR_WARNING, "%s", buf); + } + + +@@ -564,6 +564,10 @@ + static byte **BWmap; + static byte **PALmap; + ++/* XXXX Work around some collisions with the new library. */ ++#define tileContigRoutine _tileContigRoutine ++#define tileSeparateRoutine _tileSeparateRoutine ++ + typedef void (*tileContigRoutine) PARM((byte*, u_char*, RGBvalue*, + uint32, uint32, int, int)); + +@@ -603,7 +607,7 @@ + uint32, uint32, int, int)); + static void put4bitbwtile PARM((byte *, u_char *, RGBvalue *, + uint32, uint32, int, int)); +-static void put16bitbwtile PARM((byte *, u_char *, RGBvalue *, ++static void put16bitbwtile PARM((byte *, u_short *, RGBvalue *, + uint32, uint32, int, int)); + + static void putRGBcontig8bittile PARM((byte *, u_char *, RGBvalue *, +@@ -653,7 +657,7 @@ + + default: + TIFFError(TIFFFileName(tif), +- "Sorry, can not handle %d-bit pictures", bitspersample); ++ "Sorry, cannot handle %d-bit pictures", bitspersample); + return (0); + } + +@@ -666,7 +670,7 @@ + + default: + TIFFError(TIFFFileName(tif), +- "Sorry, can not handle %d-channel images", samplesperpixel); ++ "Sorry, cannot handle %d-channel images", samplesperpixel); + return (0); + } + +@@ -1157,7 +1161,7 @@ + b = g + stripsize; + put = pickTileSeparateCase(Map); + if (put == 0) { +- TIFFError(filename, "Can not handle format"); ++ TIFFError(filename, "Cannot handle format"); + return (0); + } + y = setorientation(tif, h); +@@ -1197,7 +1201,7 @@ + /* + * Greyscale images with less than 8 bits/sample are handled + * with a table to avoid lots of shifts and masks. The table +- * is setup so that put*bwtile (below) can retrieve 8/bitspersample ++ * is set up so that put*bwtile (below) can retrieve 8/bitspersample + * pixel values simply by indexing into the table with one + * number. + */ +@@ -1249,11 +1253,11 @@ + + + /* +- * Palette images with <= 8 bits/sample are handled +- * with a table to avoid lots of shifts and masks. The table +- * is setup so that put*cmaptile (below) can retrieve 8/bitspersample +- * pixel values simply by indexing into the table with one +- * number. ++ * Palette images with <= 8 bits/sample are handled with ++ * a table to avoid lots of shifts and masks. The table ++ * is set up so that put*cmaptile (below) can retrieve ++ * (8/bitspersample) pixel-values simply by indexing into ++ * the table with one number. + */ + static int makecmap() + { +@@ -1305,7 +1309,7 @@ + /* + * The following routines move decoded data returned + * from the TIFF library into rasters filled with packed +- * ABGR pixels (i.e. suitable for passing to lrecwrite.) ++ * ABGR pixels (i.e., suitable for passing to lrecwrite.) + * + * The routines have been created according to the most + * important cases and optimized. pickTileContigCase and +@@ -1376,7 +1380,7 @@ + int fromskew, toskew; + { + while (h-- > 0) { +- UNROLL8(w, , *cp++ = PALmap[*pp++][0]) ++ UNROLL8(w, , *cp++ = PALmap[*pp++][0]); + cp += toskew; + pp += fromskew; + } +@@ -1529,7 +1533,7 @@ + */ + static void put16bitbwtile(cp, pp, Map, w, h, fromskew, toskew) + byte *cp; +- u_char *pp; ++ u_short *pp; + RGBvalue *Map; + uint32 w, h; + int fromskew, toskew; +@@ -1538,8 +1542,7 @@ + + while (h-- > 0) { + for (x=w; x>0; x--) { +- *cp++ = Map[(pp[0] << 8) + pp[1]]; +- pp += 2; ++ *cp++ = Map[*pp++]; + } + cp += toskew; + pp += fromskew; +@@ -1577,7 +1580,7 @@ + *cp++ = pp[0]; + *cp++ = pp[1]; + *cp++ = pp[2]; +- pp += samplesperpixel) ++ pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +@@ -1650,7 +1653,7 @@ + *cp++ = *r++; + *cp++ = *g++; + *cp++ = *b++; +- ) ++ ); + SKEW(r, g, b, fromskew); + cp += toskew; + } +@@ -1857,7 +1860,7 @@ + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + switch (bitspersample) { +- case 16: put = put16bitbwtile; break; ++ case 16: put = (tileContigRoutine) put16bitbwtile; break; + case 8: put = putgreytile; break; + case 4: put = put4bitbwtile; break; + case 2: put = put2bitbwtile; break; +@@ -1872,7 +1875,7 @@ + break; + } + +- if (put==0) TIFFError(filename, "Can not handle format"); ++ if (put==0) TIFFError(filename, "Cannot handle format"); + return (put); + } + +@@ -1880,8 +1883,8 @@ + /* + * Select the appropriate conversion routine for unpacked data. + * +- * NB: we assume that unpacked single channel data is directed +- * to the "packed routines. ++ * NB: we assume that unpacked single-channel data is directed ++ * to the "packed" routines. + */ + static tileSeparateRoutine pickTileSeparateCase(Map) + RGBvalue* Map; +@@ -1897,10 +1900,32 @@ + break; + } + +- if (put==0) TIFFError(filename, "Can not handle format"); ++ if (put==0) TIFFError(filename, "Cannot handle format"); + return (put); + } + + + ++/*******************************************/ ++void ++VersionInfoTIFF() /* GRR 19980605 */ ++{ ++ char temp[1024], *p, *q; ++ ++ strcpy(temp, TIFFGetVersion()); ++ p = temp; ++ while (!isdigit(*p)) ++ ++p; ++ if ((q = strchr(p, '\n')) != NULL) ++ *q = '\0'; ++ ++ fprintf(stderr, " Compiled with libtiff %s", p); ++#ifdef TIFFLIB_VERSION ++ fprintf(stderr, " of %d", TIFFLIB_VERSION); /* e.g., 19960307 */ ++#endif ++ fprintf(stderr, ".\n"); ++} ++ ++ ++ + #endif /* HAVE_TIFF */ +diff -ruN xv-3.10a-bugfixes/xvtiffwr.c xv-3.10a-enhancements/xvtiffwr.c +--- xv-3.10a-bugfixes/xvtiffwr.c 2005-03-28 08:39:52.000000000 -0800 ++++ xv-3.10a-enhancements/xvtiffwr.c 2005-04-17 14:45:28.000000000 -0700 +@@ -86,6 +86,9 @@ + TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS, + GROUP3OPT_2DENCODING+GROUP3OPT_FILLBITS); + ++ if (comp == COMPRESSION_LZW) ++ TIFFSetField(tif, TIFFTAG_PREDICTOR, 2); ++ + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); +diff -ruN xv-3.10a-bugfixes/xvvd.c xv-3.10a-enhancements/xvvd.c +--- xv-3.10a-bugfixes/xvvd.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvvd.c 2005-04-17 22:56:02.000000000 -0700 +@@ -0,0 +1,1101 @@ ++ ++/* ++ * xvvd.c - extract archived file automatically and regard it as a ++ * (virtual) directory. ++ */ ++ ++#define NEEDSDIR ++ ++#include "xv.h" ++ ++#ifdef AUTO_EXPAND ++ ++static void vd_Dirtovd PARM((char *)); ++static void vd_Vdtodir PARM((char *)); ++static int vd_Mkvdir PARM((char *)); ++static int vd_Rmvdir PARM((char *)); ++static int vd_Movevdir PARM((char *, char *)); ++static void vd_addvdtable PARM((char *)); ++static void vd_packvdtable PARM((void)); ++static int vd_recursive_mkdir PARM((char *)); ++static int vd_recursive_rmdir PARM((char *)); ++static void vd_optimize_path PARM((char *)); ++static int vd_ftype PARM((char *)); ++static int vd_compp PARM((char *, char *)); ++static int vd_UncompressFile PARM((char *, char *)); ++static int vd_tarc PARM((char *)); ++static u_int vd_tar_sumchk PARM((char *)); ++ ++#define VD_VDTABLESIZE 100 ++ ++#define VD_ERR -2 ++#define VD_UKN -1 ++ ++static char *ext_command[] = { ++/* KEEP 0 */ ++ NULL, ++#define VD_ARC 1 ++ "arc xo %s", ++#define VD_ARJ 2 ++ "unarj x %s", ++#define VD_LZH 3 ++ "lha -xf %s", ++#define VD_TAR 4 ++ "tar xvf %s", ++#define VD_ZIP 5 ++ "unzip -xo %s", ++#define VD_ZOO 6 ++ "zoo xOS %s", ++}; ++ ++int vdcount = 0; ++ ++static char vdroot[MAXPATHLEN+1]; ++static char *vdtable[VD_VDTABLESIZE]; ++ ++/* ++ * These functions initialize and settle virtual directory system. ++ * Vdinit: ++ * creates root of virtual directory. ++ * Vdsettle: ++ * sweeps virtual directories. ++ */ ++void Vdinit() ++{ ++#ifndef VMS ++ char tmp[MAXPATHLEN+1]; ++ ++ xv_getwd(tmp, MAXPATHLEN+1); ++ if (chdir(tmpdir)) { ++ fprintf(stderr, "Warning: cannot chdir to tmpdir = '%s'.\n", tmpdir); ++ fprintf(stderr, ++ " I will use current directory '%s' instead of tmpdir.\n", ++ tmp); ++ } ++ xv_getwd(vdroot, MAXPATHLEN+1); ++ strcat(vdroot, "/.xvvdXXXXXX"); ++ chdir(tmp); ++#else ++ sprintf(vdroot, "Sys$Scratch:xvvdXXXXXX"); ++#endif /* VMS */ ++#ifdef USE_MKSTEMP ++ close(mkstemp(vdroot)); ++#else ++ mktemp(vdroot); ++#endif ++ ++ if (!vd_recursive_mkdir(vdroot)) ++ tmpdir = vdroot; ++} ++ ++void Vdsettle() ++{ ++ int i; ++ ++ for (i = 0; i < vdcount; i++) ++ free(vdtable[i]); ++ ++ vdcount = 0; ++ ++ vd_recursive_rmdir(vdroot); ++} ++ ++/* ++ * This function chdir to virtual directory, if specified path is in ++ * virtual directlry. ++ */ ++int Chvdir(dir) ++char *dir; ++{ ++ char buf[MAXPATHLEN+1]; ++ ++ if (Mkvdir(dir) == VD_ERR) ++ return -1; ++ ++ strcpy(buf, dir); ++ Dirtovd(buf); ++ ++ return (chdir(buf)); ++} ++ ++/* ++ * These functions convert directory <-> virtual directory. ++ * Dirtovd: ++ * front interface of vd_Dirtovd. ++ * vd_Dirtovd: ++ * converts directory to virtual directory. ++ * Vdtodir: ++ * front interface of vd_Vdtodir. ++ * vd_Vdtodir: ++ * converts virtual directory to normal directory. ++ * Dirtosubst: ++ * converts directory to substance of archive. ++ */ ++void Dirtovd(dir) ++char *dir; ++{ ++ vd_optimize_path(dir); ++ ++ vd_Dirtovd(dir); ++} ++ ++static void vd_Dirtovd(dir) ++char *dir; ++{ ++ int i; ++ ++ for (i = 0; i < vdcount; i++) ++ if (!strncmp(dir, vdtable[i], strlen(vdtable[i]))) { ++ char tmp[MAXPATHLEN+1]; ++ ++ sprintf(tmp, "%s%s", vdroot, dir); ++ strcpy(dir, tmp); ++ Dirtovd(dir); ++ } ++} ++ ++void Vdtodir(dir) ++char *dir; ++{ ++ vd_optimize_path(dir); ++ ++ vd_Vdtodir(dir); ++} ++ ++static void vd_Vdtodir(vd) ++char *vd; ++{ ++ int i; ++ char tmp[MAXPATHLEN+1]; ++ ++ for (i = vdcount-1; i >= 0; i--) { ++ sprintf(tmp, "%s%s", vdroot, vdtable[i]); ++ if(!strncmp(vd, tmp, strlen(tmp))) { ++ strcpy(tmp, vd+strlen(vdroot)); ++ strcpy(vd, tmp); ++ Vdtodir(vd); ++ } ++ } ++} ++ ++void Dirtosubst(dir) ++char *dir; ++{ ++ char tmp[MAXPATHLEN+1]; ++ ++ Dirtovd(dir); ++ ++ strcpy(tmp, dir+strlen(vdroot)); ++ ++ if (Isarchive(tmp)) ++ strcpy(dir, tmp); ++} ++ ++/* ++ * These functions make virtual directory and extracts archive, if ++ * specified path is archive. ++ * Mkvdir: ++ * front interface of vd_Mkvdir. ++ * vd_Mkvdir: ++ * does real work. ++ * Mkvdir_force: (used by makeThumbDir(in xvbrowse.c) only) ++ * make virtual directory by force. ++ */ ++int Mkvdir(dir) ++char *dir; ++{ ++ char dir1[MAXPATHLEN+1], dir2[MAXPATHLEN+1]; ++ char *d1, *d2; ++ int rv; ++ ++#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED) ++ sighold(SIGHUP); ++ sighold(SIGCHLD); ++#else ++ int mask; ++ mask = sigblock(sigmask(SIGHUP)|sigmask(SIGCHLD)); ++#endif ++ ++ strcpy(dir1, dir); ++ vd_optimize_path(dir1); ++ ++ if ((rv = vd_Mkvdir(dir1)) != VD_ERR) ++ goto MKVDIR_END; ++ ++ strcpy(dir2, dir1); ++ d2 = dir2 + strlen(dir2); ++ while (rv == VD_ERR) { ++ d2--; ++ while (*d2 != '/') ++ d2--; ++ *d2 = '\0'; ++ rv = vd_Mkvdir(dir2); ++ } ++ d1 = dir1 + strlen(dir2); ++ while ((rv != VD_ERR) && (*d1 != '\0')) { ++ *d2++ = *d1++; ++ while ((*d1 != '/') && (*d1 != '\0')) ++ *d2++ = *d1++; ++ *d2 = '\0'; ++ rv = vd_Mkvdir(dir2); ++ } ++ ++MKVDIR_END: ++#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED) ++ sigrelse(SIGHUP); ++ sigrelse(SIGCHLD); ++#else ++ sigsetmask(mask); ++#endif ++ ++ return rv; ++} ++ ++static int vd_Mkvdir(dir) ++char *dir; ++{ ++ char dir1[MAXPATHLEN+1], dir2[MAXPATHLEN+1], tmp[MAXPATHLEN+1]; ++ int ftype, i; ++ struct stat st; ++ FILE *pfp; ++ ++ strcpy(dir1, dir); ++ Dirtovd(dir1); ++ strcpy(dir2, dir1); ++ ++ WaitCursor(); ++ ++ if ((ftype = vd_ftype(dir1)) < 0) { ++ SetCursors(-1); ++ return ftype; ++ } ++ if (ftype == RFT_COMPRESS) { ++ if (!(ftype = vd_compp(dir1, tmp))) { ++ SetCursors(-1); ++ return ftype; ++ } ++ strcpy(dir1, tmp); ++ } ++ ++ if (!stat(dir1, &st)) { ++ for(i = 0; i < vdcount; i++) ++ if (!strcmp(vdtable[i], dir2)) { ++ SetCursors(-1); ++ return 0; ++ } ++ ++ if (!S_ISDIR(st.st_mode)) { ++ char origdir[MAXPATHLEN+1], buf[MAXPATHLEN+10], buf1[100]; ++ ++ if (vdcount >= VD_VDTABLESIZE) { ++ ErrPopUp("Sorry, you can't make virtual directory any more.", ++ "\nBummer!"); ++ goto VD_MKVDIR_ERR; ++ } ++ ++ WaitCursor(); ++ ++ xv_getwd(origdir, MAXPATHLEN+1); ++ ++ sprintf(tmp, "%s%s", vdroot, dir2); ++ if (vd_recursive_mkdir(tmp) || chdir(tmp)) { ++ SetISTR(ISTR_INFO, "fail to make virtual directory."); ++ Warning(); ++ goto VD_MKVDIR_ERR; ++ } ++ sprintf(buf, ext_command[ftype], dir1); ++ ++ WaitCursor(); ++ ++ if((pfp = popen(buf, "r")) == NULL) { ++ SetISTR(ISTR_INFO, "fail to extract archive '%s'.", ++ BaseName(dir2)); ++ Warning(); ++ goto VD_MKVDIR_ERR; ++ } ++ while (1) { ++ if (fread(buf1, 1, sizeof(buf1), pfp) < sizeof(buf1)) ++ break; ++ WaitCursor(); ++ } ++ if (!feof(pfp)) { ++ SetISTR(ISTR_INFO, "Pipe was broken."); ++ Warning(); ++ pclose(pfp); ++ goto VD_MKVDIR_ERR; ++ } ++ pclose(pfp); ++ ++ if (strcmp(dir1, dir2)) ++ unlink(dir1); ++ ++ vd_addvdtable(dir2); ++ Dirtovd(origdir); ++ chdir(origdir); ++ SetCursors(-1); ++ return 0; ++ ++VD_MKVDIR_ERR: ++ if (strcmp(dir1, dir2)) ++ unlink(dir1); ++ SetCursors(-1); ++ return VD_ERR; ++ } ++ } ++ SetCursors(-1); ++ return VD_ERR; ++} ++ ++#ifdef VIRTUAL_TD ++void Mkvdir_force(dir) ++char *dir; ++{ ++ char tmp[MAXPATHLEN+1]; ++ ++ if (vdcount >= VD_VDTABLESIZE) { ++ ErrPopUp("Sorry, you can't make virtual directory any more.", ++ "\nBummer!"); ++ return; ++ } ++ ++ sprintf(tmp, "%s%s", vdroot, dir); ++ if (vd_recursive_mkdir(tmp)) { ++ SetISTR(ISTR_INFO, "Failed to make virtual directory."); ++ Warning(); ++ return; ++ } ++ ++ vd_addvdtable(dir); ++} ++#endif /* VIRTUAL_TD */ ++ ++/* ++ * These functions remove virtual directory, if exists. ++ * Rmvdir: ++ * front interface of vd_Rmvdir. ++ * vd_Rmvdir: ++ * remove virtual directory function. ++ */ ++int Rmvdir(dir) ++char *dir; ++{ ++ int rv; ++ char buf[MAXPATHLEN+1]; ++ ++ strcpy(buf, dir); ++ vd_optimize_path(buf); ++ ++ rv = vd_Rmvdir(buf); ++ vd_packvdtable(); ++ return rv; ++} ++ ++static int vd_Rmvdir(dir) ++char *dir; ++{ ++ int i; ++ char tmp[MAXPATHLEN+1]; ++ ++ for(i = 0; i < vdcount; i++) ++ if (!strncmp(dir, vdtable[i], strlen(dir))) { ++ sprintf(tmp, "%s%s", vdroot, vdtable[i]); ++ if (vd_Rmvdir(tmp)) ++ return 1; ++ if (vd_recursive_rmdir(tmp)) ++ return 1; ++ vdtable[i][0] = '\0'; ++ } ++ return 0; ++} ++ ++/* ++ * These functions move virtual directory, if exists. ++ * Movevdir: ++ * front interface of move virtual directory function. ++ * vd_Movevdir: ++ * does real work. ++ */ ++int Movevdir(src, dst) ++char *src, *dst; ++{ ++/* ++ char sbuf[MAXPATHLEN+1], dbuf[MAXPATHLEN+1]; ++ ++ strcpy(sbuf, src); ++ vd_optimize_path(sbuf); ++ ++ strcpy(dbuf, dst); ++ vd_optimize_path(dbuf); ++ ++ return (vd_Movevdir(sbuf, dbuf)); ++*/ ++ return (vd_Movevdir(src, dst)); ++} ++ ++static int vd_Movevdir(src, dst) ++char *src, *dst; ++{ ++ int i; ++ char *p, *pp; ++ char tmp[MAXPATHLEN+1], tmps[MAXPATHLEN+1], tmpd[MAXPATHLEN+1]; ++ ++ for (i = 0; i < vdcount; i++) ++ if (!strncmp(src, vdtable[i], strlen(src))) { ++ sprintf(tmps, "%s%s", vdroot, vdtable[i]); ++ sprintf(tmp, "%s%s", dst, vdtable[i]+strlen(src)); ++ sprintf(tmpd, "%s%s", vdroot, tmp); ++ ++ if (vd_Movevdir(tmps, tmpd)) ++ return 1; ++ ++ pp = vdtable[i]; ++ p = (char *) malloc(strlen(tmp)+1); ++ strcpy(p, tmp); ++ vdtable[i] = p; ++ ++ strcpy(tmp, tmpd); ++ for (p = tmp+strlen(tmp); *p != '/'; p--) ++ ; ++ *p = '\0'; ++ ++ if (vd_recursive_mkdir(tmp)) ++ goto VD_MOVEVDIR_ERR; ++ ++ if (rename(tmps, tmpd) < 0) ++ goto VD_MOVEVDIR_ERR; ++ ++ free(pp); ++ } ++ return 0; ++ ++VD_MOVEVDIR_ERR: ++ free(vdtable[i]); ++ vdtable[i] = pp; ++ return 1; ++} ++ ++/* ++ * These functions handle table of virtual directories. ++ * vd_addvdtable: ++ * adds virtual directory to table. ++ * vd_packvdtable: ++ * removes disused virtual directories from table. ++ */ ++static void vd_addvdtable(vd) ++char *vd; ++{ ++ char *p; ++ p = (char *) malloc(strlen(vd)+1); ++ strcpy(p, vd); ++ vdtable[vdcount] = p; ++ vdcount++; ++} ++ ++static void vd_packvdtable() ++{ ++ int i, j; ++ ++ for (i = j = 0; i < vdcount; i++) ++ if (vdtable[i][0] != '\0') ++ vdtable[j++] = vdtable[i]; ++ else ++ free(vdtable[i]); ++ ++ vdcount = j; ++} ++ ++/* ++ * These are utility functions. ++ * vd_recursive_mkdir: ++ * makes directories recursively. ++ * vd_recursive_rmdir ++ * removes directories recursively. ++ */ ++static int vd_recursive_mkdir(dir) ++char *dir; ++{ ++ char buf[MAXPATHLEN+1], *p; ++ struct stat st; ++ ++ strcpy(buf, dir); ++ ++ if (buf[strlen(buf) - 1] == '/') ++ buf[strlen(buf) - 1] = '\0'; ++ ++ p = rindex(buf, '/'); ++ *p = '\0'; ++ ++ if (stat(buf, &st) < 0) ++ if (vd_recursive_mkdir(buf) < 0) ++ return (-1); ++ ++ *p = '/'; ++ if (mkdir(buf, 0700) < 0) ++ return (-1); ++ ++ return (0); ++} ++ ++static int vd_recursive_rmdir(dir) ++char *dir; ++{ ++ char buf[MAXPATHLEN+1], buf2[MAXPATHLEN+1]; ++ DIR *dp; ++ struct dirent *di; ++ ++ strcpy(buf, dir); ++ ++ if (buf[strlen(buf) - 1] == '/') ++ buf[strlen(buf) - 1] = '\0'; ++ ++ if ((dp = opendir(buf)) == NULL) ++ return (-1); ++ ++ while ((di = readdir(dp)) != NULL) { ++ struct stat st; ++ ++ if (!strcmp(di->d_name, ".") || !strcmp(di->d_name, "..")) ++ continue; ++ ++ sprintf(buf2, "%s/%s", dir, di->d_name); ++ ++ stat(buf2, &st); ++ if (S_ISDIR(st.st_mode)) { ++ if (vd_recursive_rmdir(buf2) < 0) ++ goto VD_RECURSIVE_RMDIR_ERR; ++ } else ++ unlink(buf2); ++ } ++ if (rmdir(buf) < 0) ++ goto VD_RECURSIVE_RMDIR_ERR; ++ ++ closedir(dp); ++ return (0); ++ ++VD_RECURSIVE_RMDIR_ERR: ++ closedir(dp); ++ return (-1); ++} ++ ++/* ++ * These functions test specified path. ++ * Isarchive: ++ * tests whether it's an archive? ++ * Isvdir: ++ * tests whether it's in the virtual directory? ++ */ ++int Isarchive(path) ++char *path; ++{ ++ int ftype; ++ ++ if ((ftype = vd_ftype(path)) < 0) ++ return 0; ++ ++ if (ftype == RFT_COMPRESS) ++ if (!(ftype = vd_compp(path, NULL))) ++ return 0; ++ ++ return ftype; ++} ++ ++int Isvdir(path) ++char *path; ++{ ++ int rv = 0; ++ char tmp1[MAXPATHLEN+1], tmp2[MAXPATHLEN+1]; ++ int archive1, archive2; ++ ++ strcpy(tmp1, path); ++ strcpy(tmp2, path); ++ ++ vd_optimize_path(tmp1); ++ Dirtovd(tmp2); ++ ++ archive1 = Isarchive(tmp1); ++ archive2 = Isarchive(tmp2); ++ ++ if (strcmp(tmp1, tmp2)) { ++ char tmp3[MAXPATHLEN+1], tmp4[MAXPATHLEN+1]; ++ int archive3, archive4; ++ ++ sprintf(tmp3, "%s%s", vdroot, tmp1); ++ strcpy(tmp4, tmp2+strlen(vdroot)); ++ ++ archive3 = Isarchive(tmp3); ++ archive4 = Isarchive(tmp4); ++ ++ if (archive4 && !strcmp(tmp1, tmp4)) { ++ rv |= 06; ++ return rv; ++ } ++ rv |= 01; ++ if (archive2) ++ rv |= 02; ++ else if (archive4) ++ rv |= 06; ++ return rv; ++ } ++ if (archive1) ++ rv |= 02; ++ ++ return rv; ++} ++ ++/* ++ * This function optimizes given path. ++ * Expand '~' to home directory and removes '.', and treat '..'. ++ */ ++static void vd_optimize_path(path) ++char *path; ++{ ++ char *tmp, *reserve; ++ ++ if (!strcmp(path, STDINSTR)) ++ return; ++ ++ if (*path == '\0') { ++ xv_getwd(path, MAXPATHLEN+1); ++ return; ++ } ++ if (*path == '~') ++ Globify(path); ++ if (*path != '/') { ++ char tmp[MAXPATHLEN+1]; ++ ++ strcpy(tmp, path); ++ xv_getwd(path, MAXPATHLEN+1); ++ strcat(path, "/"); ++ strcat(path, tmp); ++ } ++ ++ reserve = tmp = path; ++ while(*path != '\0') { ++ if (*path == '/') { ++ *tmp++ = *path; ++ while (*++path == '/') ++ ; ++ continue; ++ } ++ if ((*path == '.') && (*(path-1) == '/')) { ++ if (*(path+1) == '/') { ++ tmp--; ++ path++; ++ continue; ++ } else if (*(path+1) == '\0') { ++ tmp--; ++ break; ++ } else if (*(path+1) == '.') { ++ if (*(path+2) == '/') { ++ if ((tmp - reserve) > 1) ++ for (tmp-=2; (*tmp != '/'); tmp--) ++ ; ++ else ++ tmp = reserve; ++ path+=2; ++ continue; ++ } else if (*(path+2) == '\0') { ++ if ((tmp - reserve) > 1) ++ for (tmp-=2; (*tmp != '/'); tmp--) ++ ; ++ else ++ tmp = reserve+1; ++ break; ++ } ++ } ++ } ++ *tmp++ = *path++; ++ } ++ if (((tmp - reserve) > 1) && *(tmp-1) == '/') ++ tmp--; ++ if (tmp == reserve) ++ *tmp++ = '/'; ++ ++ *tmp = '\0'; ++} ++ ++/* ++ * These functions detect file type. ++ */ ++static int vd_ftype(fname) ++char *fname; ++{ ++ /* check archive type */ ++ ++ FILE *fp; ++ byte magicno[30]; /* first 30 bytes of file */ ++ int rv, n; ++ struct stat st; ++ ++ if (!fname) return VD_ERR; /* shouldn't happen */ ++ ++ if ((!stat(fname, &st)) && (st.st_mode & S_IFMT) == S_IFDIR) ++ return VD_UKN; ++ fp = xv_fopen(fname, "r"); ++ if (!fp) return VD_ERR; ++ ++ n = fread(magicno, (size_t) 1, (size_t) 30, fp); ++ fclose(fp); ++ ++ if (n<30) return VD_UKN; /* files less than 30 bytes long... */ ++ ++ rv = VD_UKN; ++ ++ if (magicno[0] == 0x60 && magicno[1]==0xea) rv = VD_ARJ; ++ ++ else if (magicno[2] == '-' && magicno[3] == 'l' && ++ magicno[4] == 'h') rv = VD_LZH; ++ ++ else if (strncmp((char *) magicno,"PK", (size_t) 2)==0) rv = VD_ZIP; ++ ++ else if (magicno[20]==0xdc && magicno[21]==0xa7 && ++ magicno[22]==0xc4 && magicno[23]==0xfd) rv = VD_ZOO; ++ ++ else if (vd_tarc(fname)) rv = VD_TAR; ++ ++ else if (magicno[0]==0x1f && magicno[1]==0x9d) rv = RFT_COMPRESS; ++ ++ else if (!strncmp((char *) &magicno[11], "MAJYO", (size_t) 5)) ++ rv = VD_UKN; /* XXX */ ++ ++ else if (magicno[0] == 26) rv = VD_ARC; ++ ++#ifdef GUNZIP ++ else if (magicno[0]==0x1f && magicno[1]==0x8b) rv = RFT_COMPRESS;/* gzip */ ++ else if (magicno[0]==0x1f && magicno[1]==0x9e) rv = RFT_COMPRESS;/* old */ ++ else if (magicno[0]==0x1f && magicno[1]==0x1e) rv = RFT_COMPRESS;/* pack */ ++#endif ++ ++ return rv; ++} ++ ++static int vd_compp(path, newpath) ++char *path, *newpath; ++{ ++ /* ++ * uncompress and check archive type. ++ * ++ * If newpath is NULL, uncompress only 512 byte of 'path' and ++ * check archive type, so it is for SPEED-UP strategy. ++ * In this case, caller this function does not have to unlink ++ * tempoary file. ++ * Unfortunately it does not work in VMS system. ++ */ ++ ++ int file_type, r; ++ char uncompname[128], basename[128]; ++ int comptype; ++ ++ if (newpath) *newpath = '\0'; ++ strncpy(basename, path, 127); ++ comptype = ReadFileType(path); ++#if (defined(VMS) && !defined(GUNZIP)) ++ /* VMS decompress doesn't like the file to have a trailing .Z in fname ++ however, GUnZip is OK with it, which we are calling UnCompress */ ++ *rindex (basename, '.') = '\0'; ++#endif ++#ifdef VMS ++ if (UncompressFile(basename, uncompname)) { ++#else ++ if (newpath == NULL) ++ r = vd_UncompressFile(basename, uncompname); ++ else ++ r = UncompressFile(basename, uncompname, comptype); ++ if (r) { ++#endif ++ if ((file_type = vd_ftype(uncompname)) < 0) { ++ unlink(uncompname); ++ return 0; ++ } ++ if (newpath) strcpy(newpath, uncompname); ++ else unlink(uncompname); ++ } else { ++ return 0; ++ } ++ return file_type; ++} ++ ++#define HEADERSIZE 512 ++ ++static void vd_Dirtovd PARM((char *)); ++static int stderr_on PARM((void)); ++static int stderr_off PARM((void)); ++static FILE *popen_nul PARM((char *, char *)); ++ ++static int vd_UncompressFile(name, uncompname) ++char *name, *uncompname; ++{ ++ /* Yap, I`m nearly same as original `UncompnameFile' function, but, ++ 1) I extract `name' file ONLY first 512 byte. ++ 2) I'm called only from UNIX and UNIX like OS, *NOT* VMS */ ++ /* returns '1' on success, with name of uncompressed file in uncompname ++ returns '0' on failure */ ++ ++ char namez[128], *fname, buf[512], tmp[HEADERSIZE]; ++ int n, tmpfd; ++ FILE *pfp, *tfp; ++ ++ fname = name; ++ namez[0] = '\0'; ++ ++ ++#ifndef GUNZIP ++ /* see if compressed file name ends with '.Z'. If it *doesn't*, we need ++ to temporarily rename it so it *does*, uncompress it, and rename it ++ *back* to what it was. necessary because uncompress doesn't handle ++ files that don't end with '.Z' */ ++ ++ if (strlen(name) >= (size_t) 2 && ++ strcmp(name + strlen(name)-2,".Z")!=0 && ++ strcmp(name + strlen(name)-2,".z")!=0) { ++ strcpy(namez, name); ++ strcat(namez,".Z"); ++ ++ if (rename(name, namez) < 0) { ++ sprintf(buf, "Error renaming '%s' to '%s': %s", ++ name, namez, ERRSTR(errno)); ++ ErrPopUp(buf, "\nBummer!"); ++ return 0; ++ } ++ ++ fname = namez; ++ } ++#endif /* not GUNZIP */ ++ ++ sprintf(uncompname, "%s/xvuXXXXXX", tmpdir); ++#ifdef USE_MKSTEMP ++ tmpfd = mkstemp(uncompname); ++#else ++ mktemp(uncompname); ++#endif ++ ++ sprintf(buf,"%s -c %s", UNCOMPRESS, fname); ++ SetISTR(ISTR_INFO, "Uncompressing Header '%s'...", BaseName(fname)); ++ if ((pfp = popen_nul(buf, "r")) == NULL) { ++ SetISTR(ISTR_INFO, "Cannot extract for archive '%s'.", ++ BaseName(fname)); ++ Warning(); ++#ifdef USE_MKSTEMP ++ if (tmpfd >= 0) ++ close(tmpfd); ++#endif ++ return 0; ++ } ++#ifdef USE_MKSTEMP ++ if (tmpfd < 0) ++#else ++ if ((tmpfd = open(uncompname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR)) < 0) ++#endif ++ { ++ SetISTR(ISTR_INFO, "Unable to create temporary file.", ++ BaseName(uncompname)); ++ Warning(); ++ pclose(pfp); ++ } ++ if ((tfp = fdopen(tmpfd, "w")) == NULL) { ++ SetISTR(ISTR_INFO, "Unable to create temporary file.", ++ BaseName(uncompname)); ++ Warning(); ++ close(tmpfd); ++ pclose(pfp); ++ return 0; ++ } ++ if ((n = fread(tmp, 1, sizeof(tmp), pfp)) != HEADERSIZE) { ++ SetISTR(ISTR_INFO, "Unable to read '%s'.", ++ BaseName(fname)); ++ Warning(); ++ pclose(pfp); ++ fflush(tfp); ++ fclose(tfp); ++ close(tmpfd); ++ return 0; ++ } ++ fwrite(tmp, 1, n, tfp); ++ fflush(tfp); ++ fclose(tfp); ++ close(tmpfd); ++ pclose(pfp); ++ ++ /* if we renamed the file to end with a .Z for the sake of 'uncompress', ++ rename it back to what it once was... */ ++ ++ if (strlen(namez)) { ++ if (rename(namez, name) < 0) { ++ sprintf(buf, "Error renaming '%s' to '%s': %s", ++ namez, name, ERRSTR(errno)); ++ ErrPopUp(buf, "\nBummer!"); ++ } ++ } ++ ++ return 1; ++} ++ ++#define TARBLOCK 512 ++#define CKSTART 148 /* XXX */ ++#define CKSIZE 8 ++ ++/* ++ * Tar file: 1, other: 0 ++ */ ++static int vd_tarc(fname) ++char *fname; ++{ ++ FILE *fp; ++ unsigned int sum; ++ char *ckp, buf[TARBLOCK]; ++ ++ if ((fp = fopen(fname, "r")) == NULL) ++ return 0; ++ ++ fread(buf, TARBLOCK, 1, fp); ++ fclose(fp); ++ ++ for (sum = 0, ckp = buf + CKSTART; ++ (ckp < buf + CKSTART + CKSIZE) && *ckp != '\0'; ++ ckp++) { ++ sum *= 8; ++ if (*ckp == ' ') ++ continue; ++ if (*ckp < '0' || '7' < *ckp) ++ return 0; ++ sum += *ckp - '0'; ++ } ++ if (sum != vd_tar_sumchk(buf)) ++ return 0; ++ ++ return 1; ++} ++ ++static unsigned int vd_tar_sumchk(buf) ++char *buf; ++{ ++ int i; ++ unsigned int sum = 0; ++ ++ for (i = 0; i < CKSTART; i++) { ++ sum += *(buf + i); ++ } ++ sum += ' ' * 8; ++ for (i += 8; i < TARBLOCK; i++) { ++ sum += *(buf + i); ++ } ++ return sum; ++} ++ ++ ++static int stde = -1; /* fd of stderr */ ++static int nul = -1; /* fd of /dev/null */ ++ ++/* ++ * switch off the output to stderr(bypass to /dev/null). ++ */ ++static int stderr_off() ++{ ++ if (nul < 0) ++ nul = open("/dev/null", O_RDONLY); ++ if (nul < 0) { ++ fprintf(stderr, "/dev/null open failure\n"); ++ return -1; ++ } ++ if (stde < 0) ++ stde = dup(2); ++ if (stde < 0) { ++ fprintf(stderr, "duplicate stderr failure\n"); ++ return -1; ++ } ++ close(2); ++ dup(nul); ++ return 0; ++} ++ ++/* ++ * turn on stderr output. ++ */ ++static int stderr_on() ++{ ++ if ((stde < 0) || (nul < 0)) { ++ fprintf(stderr, "stderr_on should call after stderr_off\n"); ++ return -1; ++ } ++ close(2); ++ dup(stde); ++ return 0; ++} ++ ++/* ++ * popen with no output to stderr. ++ */ ++static FILE *popen_nul(prog, mode) ++char *prog, *mode; ++{ ++ FILE *fp; ++ ++ stderr_off(); ++ fp = popen(prog, mode); ++ stderr_on(); ++ return fp; ++} ++ ++/* ++ * These functions are for SIGNAL. ++ * If XV end by C-c, there are dust of directory which name is .xvvd???, ++ * made by xvvd. Then, I handle SIGINT, and add good finish. ++ */ ++void vd_HUPhandler() ++{ ++#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED) ++ sighold(SIGHUP); ++#else ++ int mask; ++ mask = sigblock(sigmask(SIGHUP)); ++#endif ++ ++ Vdsettle(); ++ ++#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED) ++ sigrelse(SIGHUP); ++ signal(SIGHUP, (void (*)PARM((int))) vd_HUPhandler); ++#else ++ sigsetmask(mask); ++#endif ++} ++ ++void vd_handler(sig) ++int sig; ++{ ++#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED) ++ sighold(sig); ++#else ++ sigblock(sigmask(sig)); ++#endif ++ ++ Quit(1); /*exit(1);*/ ++} ++ ++int vd_Xhandler(disp,event) ++Display *disp; ++XErrorEvent *event; ++{ ++ Quit(1); /*exit(1);*/ ++ return (1); /* Not reached */ ++} ++ ++int vd_XIOhandler(disp) ++Display *disp; ++{ ++ fprintf(stderr, "XIO fatal IO error ? (?) on X server\n"); ++ fprintf(stderr, "You must exit normally in xv usage.\n"); ++ Quit(1); /*exit(1);*/ ++ return (1); /* Not reached */ ++} ++ ++void vd_handler_setup() ++{ ++ signal(SIGHUP, (void (*)PARM((int))) vd_HUPhandler); ++ signal(SIGINT, (void (*)PARM((int))) vd_handler); ++ signal(SIGTERM,(void (*)PARM((int))) vd_handler); ++ ++ (void)XSetErrorHandler(vd_Xhandler); ++ (void)XSetIOErrorHandler(vd_XIOhandler); ++} ++#endif /* AUTO_EXPAND */ +diff -ruN xv-3.10a-bugfixes/xvwbmp.c xv-3.10a-enhancements/xvwbmp.c +--- xv-3.10a-bugfixes/xvwbmp.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvwbmp.c 2005-04-03 14:02:18.000000000 -0700 +@@ -0,0 +1,323 @@ ++/* ++ * xvwbmp.c - i/o routings for WBMP files ++ * defined by OMA (http://www.openmobilealliance.com) ++ * as a standard for images for micro devices. ++ * ++ * exports : ++ * ++ * LoadWBMP(fname, numcols); ++ * WriteWBMP(fp, pic, ptype, w, h, r, g, b, numcols, style); ++ * ++ * author: Pawel S. Veselov <vps@manticore.2y.net> ++ * http://manticore.2y.net/ ++ * ++ */ ++ ++#include "xv.h" ++ ++typedef short int16; ++typedef unsigned char uint8; ++typedef unsigned short uint16; /* sizeof (uint16) must == 2 */ ++#if defined(__alpha) || _MIPS_SZLONG == 64 ++typedef int int32; ++typedef unsigned int uint32; /* sizeof (uint32) must == 4 */ ++#else ++typedef long int32; ++typedef unsigned long uint32; /* sizeof (uint32) must == 4 */ ++#endif ++ ++#define MUST(a) if (!(a)) {\ ++ return fail(st_fname, st_err);\ ++ close(fd); \ ++ } ++#define READU8(fd,u) if ((read(fd, &u, 1)<1)) {\ ++ myfree(); \ ++ close(fd); \ ++ return fail(st_fname, err_ueof); } ++#define SREADU8(fd, u) if ((read(fd, &u, 1,)<1)) {\ ++ { st_err = err_ueof; return 0; } ++ ++#define SREADC(fd, str, l) { \ ++ str = (char*)mymalloc(l); \ ++ if (!str) { \ ++ myfree(); \ ++ FatalError("LoadWBMP: can't malloc extension buffer"); \ ++ } \ ++ if (read(fd, str, l)<l) { \ ++ st_err = err_ueof; \ ++ return 0; \ ++ } ++ ++static char * err_ueof = "Unexpected EOF"; ++static char * err_unst = "Unsupported image type"; ++static char * err_extf = "Extensions are forbidden"; ++static char * err_inmb = "Invalid multibyte integer"; ++ ++static char * st_fname; ++static char * st_err; ++ ++static int fail PARM((char *, char *)); ++static int read_mb PARM((int *, int)); ++static void write_mb PARM((uint32, FILE *)); ++static int read_ext PARM((int, uint8)); ++static void * mymalloc PARM((int)); ++static void myfree PARM((void)); ++static uint8 * render1 PARM((uint8 *, int, int)); ++ ++void ** mymem = NULL; ++int mymems = 0; ++ ++int LoadWBMP(char * fname, PICINFO * pinfo) ++{ ++ int fd; ++ int im_type; /* image type (only type 0 supported) */ ++ uint8 fix_header; /* fixed header field */ ++ int width, height; ++ int npixels, raw_size, aux; ++ uint8 * raw; ++ ++ st_fname = fname; ++ ++ fd = open(fname, O_RDONLY); ++ if (fd < 0) { ++ return fail(fname, "Couldn't open the file"); ++ } ++ ++ MUST(read_mb(&im_type, fd)); ++ if (im_type) { ++ return fail(fname, err_unst); ++ } ++ ++ READU8(fd, fix_header); ++ ++ MUST(read_ext(fd, fix_header)); ++ ++ MUST(read_mb(&width, fd)); ++ MUST(read_mb(&height, fd)); ++ ++ npixels = width * height; ++ raw_size = (npixels+7) / 8; ++ if (width <= 0 || height <= 0 || npixels/width != height || ++ npixels+7 < npixels) ++ { ++ return fail(fname, "image dimensions out of range"); ++ } ++ ++ raw = mymalloc(raw_size); ++ if (!raw) { ++ myfree(); ++ FatalError("LoadWBMP: can't malloc image buffer"); ++ } ++ ++ aux = read(fd, raw, raw_size); ++ if (aux < raw_size) { ++ fail(fname, "Image size shrank"); ++ raw_size = aux; ++ } ++ ++ pinfo->r[0] = 0; ++ pinfo->g[0] = 0; ++ pinfo->b[0] = 0; ++ pinfo->r[1] = 255; ++ pinfo->g[1] = 255; ++ pinfo->b[1] = 255; ++ ++ pinfo->pic = render1(raw, raw_size, npixels); ++ pinfo->type = PIC8; ++ ++ pinfo->w = pinfo->normw = width; ++ pinfo->h = pinfo->normh = height; ++ pinfo->frmType = F_BWDITHER; ++ ++ sprintf(pinfo->fullInfo, "WBMP, 1 bit per pixel, %d bytes", raw_size); ++ sprintf(pinfo->shrtInfo, "%dx%d WBMP (WAP/OMA).", width, height); ++ pinfo->comment = (char*)NULL; ++ ++ close(fd); ++ ++ myfree(); ++ return 1; ++} ++ ++int WriteWBMP(FILE * fp, byte * pic, int ptype, int w, int h, ++ byte * rmap, byte *gmap, byte *bmap, ++ int numcols, int colorstyle) ++{ ++ int count = 0; ++ uint8 bit = 0; ++ int i; ++ ++ write_mb(0, fp); /* type : always 0 */ ++ putc(0, fp); /* fixed header : always 0 for type 0 */ ++ write_mb((uint32)w, fp); ++ write_mb((uint32)h, fp); ++ ++ /* ready to write data */ ++ ++ for (i=0; i<w*h; i++) { ++ bit |= (((pic[i]&1)<<(7-(count++)))); ++ if (count == 8) { ++ putc(bit, fp); ++ count = 0; ++ } ++ } ++ ++ if (!count) { ++ putc(bit, fp); ++ } ++ ++ return 0; ++} ++ ++int fail(char * name, char * msg) ++{ ++ SetISTR(ISTR_WARNING, "%s : %s", name, msg); ++ return 0; ++} ++ ++void write_mb(uint32 data, FILE * f) ++{ ++ int i = 32; ++ uint32 aux = data; ++ int no; ++ ++ if (!aux) { ++ i = 1; ++ } else { ++ while (!(aux & 0x80000000)) { ++ aux <<= 1; ++ i--; ++ } ++ } ++ ++ /* i tells us how many bits are left to encode */ ++ ++ no = (i / 7 + ((i % 7)?1:0))-1; ++ ++ /* ++ fprintf(stderr, "writing %x, bits to write=%d, passes=%d\n", ++ data, i, no); ++ */ ++ ++ do { ++ uint8 value = no?0x80:0x0; ++ value |= ((data >> (no*7)) & 0x7f); ++ putc(value, f); ++ } while ((no--)>0); ++ ++} ++ ++int read_mb(int * dst, int fd) ++{ ++ int ac = 0; ++ int ct = 0; ++ ++ while (1) { ++ uint8 bt; ++ if ((ct++)==6) { ++ st_err = err_inmb; ++ return 0; ++ } ++ ++ if ((read(fd, &bt, 1)) < 1) { ++ st_err = err_ueof; ++ return 0; ++ } ++ ac = (ac << 7) | (bt & 0x7f); /* accumulates up to 42 bits?? FIXME */ ++ if (!(bt & 0x80)) ++ break; ++ } ++ *dst = ac; ++ return 1; ++} ++ ++int read_ext(int fd, uint8 fixed) ++{ ++ if (!(fixed&0x7f)) { /* no extensions */ ++ return 1; ++ } ++ ++ /* ++ * The only described type is WBMP 0, that must not ++ * have extensions. ++ */ ++ ++ st_err = err_extf; ++ return 0; ++ ++ /* ++ ++ fixed = (fixed >> 5)&0x3; ++ ++ switch (fixed) { ++ case 0: ++ while (true) { ++ SREADU8(fd, fixed); ++ if (!(fixed & 0x7f)) { break; } ++ } ++ break; ++ case 0x3: ++ { ++ char * par; ++ char * val; ++ SREADU8(fd, fixed); ++ SREADC(fd, par, (fixed>>4)&0x6); ++ SREADC(fd, val, fixed&0xf); ++ } ++ break; ++ } ++ */ ++} ++ ++void * mymalloc(int l) ++{ ++ mymem = (void**)realloc(mymem, mymems+1); ++ if (!mymem) ++ FatalError("LoadWBMP: can't realloc buffer"); ++ return (mymem[mymems++] = malloc(l)); ++} ++ ++void myfree() ++{ ++ int i; ++ ++ if (mymem) { ++ for (i=0; i<mymems; i++) { ++ if (mymem[i]) ++ free(mymem[i]); ++ } ++ free(mymem); ++ } ++ mymem = (void**)NULL; ++ mymems = 0; ++} ++ ++uint8 * render1(uint8 * data, int size, int npixels) ++{ ++ byte * pic; ++ int i; ++ int cnt = 0; ++ uint8 cb = *data; ++ ++ pic = calloc(npixels,1); /* checked for overflow by caller */ ++ if (!pic) { ++ myfree(); ++ FatalError("LoadWBMP: can't allocate 'pic' buffer"); ++ } ++ ++ /* expand bits into bytes */ ++ /* memset(pic, 0, npixels); */ ++ ++ for (i=0; i<npixels; i++) { ++ ++ pic[i] = (cb>>7)&1; ++ ++ if ((++cnt)==8) { ++ cb = *(++data); ++ cnt = 0; ++ } else { ++ cb <<=1; ++ } ++ } ++ return pic; ++} +diff -ruN xv-3.10a-bugfixes/xvxpm.c xv-3.10a-enhancements/xvxpm.c +--- xv-3.10a-bugfixes/xvxpm.c 2005-03-28 22:22:50.000000000 -0800 ++++ xv-3.10a-enhancements/xvxpm.c 2005-04-17 14:45:28.000000000 -0700 +@@ -175,7 +175,15 @@ + + do { + char key[3]; +- char color[40]; /* Need to figure a good size for this... */ ++ char color[80]; /* Need to figure a good size for this... */ ++ ++/* ++ * Problem with spaces in color names ++ * ++ * X s Color Name m Other Name c Last Name ++ * ++ * ... this parser doesn't find `Any Name' ++ */ + + for (j=0; j<2 && (c != ' ') && (c != '\t') && (c != EOF); j++) { + key[j] = c; +@@ -187,7 +195,7 @@ + if (c == EOF) /* The failure condition of getc() */ + return (XpmLoadError(bname, "Error parsing colormap line")); + +- for (j=0; j<39 && (c!=' ') && (c!='\t') && (c!='"') && c!=EOF; j++) { ++ for (j=0; j<79 && (c!=' ') && (c!='\t') && (c!='"') && c!=EOF; j++) { + color[j] = c; + c = XpmGetc(fp); + } +@@ -248,7 +256,7 @@ + else { /* 'None' or unrecognized color spec */ + int rgb; + +- if (strcmp(color, "None") == 0) rgb = 0xb2c0dc; /* infobg */ ++ if (strcasecmp(color, "None") == 0) rgb = 0xb2c0dc; /* infobg */ + else { + SetISTR(ISTR_INFO, "%s: unknown color spec '%s'", bname, color); + Timer(1000); +@@ -321,7 +329,8 @@ + *i_sptr++ = mapentry->cv_rgb[2]; + } + } /* for ( j < w ) */ +- (void)XpmGetc(fp); /* Throw away the close " */ ++ while (((c = XpmGetc(fp))!=EOF) && /* Throw away the close " and */ ++ (c != '"')); /* erase all remaining pixels */ + + if (!(i%7)) WaitCursor(); + } /* for ( i < h ) */ +diff -ruN xv-3.10a-bugfixes/xvzx.c xv-3.10a-enhancements/xvzx.c +--- xv-3.10a-bugfixes/xvzx.c 1969-12-31 16:00:00.000000000 -0800 ++++ xv-3.10a-enhancements/xvzx.c 2004-05-16 18:08:33.000000000 -0700 +@@ -0,0 +1,349 @@ ++/* ++ * xvzx.c - load routine for Spectrum screen$ ++ * ++ * John Elliott, 7 August 1998 ++ * ++ * LoadZX(fname, pinfo) - load file ++ * WriteZX(fp,pic,ptype,w,h,r,g,b,numcols,style,cmt,comment) - convert to ++ * 256x192 SCREEN$ and save. ++ */ ++ ++#include "copyright.h" ++ ++#include "xv.h" ++ ++ ++ ++/* ++ * comments on error handling: ++ * a file with a bad header checksum is a warning error. ++ * ++ * not being able to malloc is a Fatal Error. The program is aborted. ++ */ ++ ++ ++#define TRUNCSTR "File appears to be truncated." ++ ++static int zxError PARM((char *, char *)); ++ ++static char *bname; ++ ++/*******************************************/ ++int LoadZX(fname, pinfo) ++ char *fname; ++ PICINFO *pinfo; ++/*******************************************/ ++{ ++ /* returns '1' on success */ ++ ++ FILE *fp; ++ unsigned int c, c1; ++ int x,y, trunc; ++ byte *zxfile; ++ ++ bname = BaseName(fname); ++ ++ pinfo->pic = (byte *) NULL; ++ pinfo->comment = (char *) NULL; ++ ++ /* Allocate memory for a 256x192x8bit image */ ++ ++ pinfo->pic = (byte *)malloc(256*192); ++ if (!pinfo->pic) FatalError("malloc failure in xvzx.c LoadZX"); ++ ++ /* Allocate 1B80h bytes and slurp the whole file into memory */ ++ ++ zxfile = (byte *)malloc(7040); ++ if (!zxfile) FatalError("malloc failure in xvzx.c LoadZX"); ++ ++ /* open the file */ ++ fp = xv_fopen(fname,"r"); ++ if (!fp) return (zxError(bname, "can't open file")); ++ ++ /* Load it in en bloc */ ++ memset(zxfile, 0, 7040); ++ if (fread(zxfile, 1, 7040, fp) < 7040) trunc = 1; ++ ++ /* Transform to 8-bit */ ++ ++ for (y = 0; y < 192; y++) for (x = 0; x < 256; x++) ++ { ++ /* Spectrum screen layout: three 2k segments at y=0, y=64, y=128 */ ++ /* In each segment: Scan lines 0,8,16,...,56,1,9,...,57 etc. Each ++ scanline is 32 bytes, so line 1 is 256 bytes after line 0 ++ ++ So address of line start is ((y>>6) * 2048) + ((y & 7) * 256) ++ + ((y & 0x38) * 4) ++ ++ The colour byte for a cell is at screen + 6k + (y >> 3)*32 + (x>>3) ++ ++ */ ++ ++ int offset; ++ byte *dst = pinfo->pic + 256*y + x; ++ byte attr, pt, mask; ++ ++ offset = (y >> 6) * 2048; ++ offset += (y & 7) * 256; ++ offset += (y & 0x38) * 4; ++ offset += (x >> 3); ++ ++ pt = zxfile[offset + 128]; /* Ink/paper map */ ++ ++ offset = 0x1880; ++ offset += (y >> 3) * 32; ++ offset += (x >> 3); ++ ++ attr = zxfile[offset]; /* Colours for cell */ ++ ++ mask = 0x80; ++ ++ if (x & 7) mask >>= (x & 7); ++ ++ if (pt & mask) *dst = attr & 7; /* Ink */ ++ else *dst = (attr >> 3) & 7; /* Paper */ ++ ++ if (attr & 0x40) *dst |= 8; /* High intensity */ ++ } ++ ++ /* Picture bytes converted; now build the colour maps */ ++ ++ pinfo->normw = pinfo->w = 256; ++ pinfo->normh = pinfo->h = 192; ++ pinfo->type = PIC8; ++ ++ for (c = 0; c < 16; c++) ++ { ++ if (c < 8) c1 = 192; else c1 = 255; /* low-intensity colours use 192 */ ++ /* high-intensity colours use 255 */ ++ pinfo->b[c] = (c & 1 ? c1 : 0); ++ pinfo->r[c] = (c & 2 ? c1 : 0); ++ pinfo->g[c] = (c & 4 ? c1 : 0); ++ } ++ ++ pinfo->colType = F_FULLCOLOR; ++ pinfo->frmType = F_ZX; /* Save as SCREEN$ */ ++ sprintf(pinfo->fullInfo, "Spectrum SCREEN$, load address %04x", ++ zxfile[16]+256*zxfile[17]); ++ strcpy(pinfo->shrtInfo, "Spectrum SCREEN$."); ++ ++ /* Almost as an afterthought, check that the +3DOS header is valid. ++ ++ If it isn't, then odds are that the file isn't a graphic. But it ++ had the right magic number, so it might be. Let them see it anyway. ++ ++ The check is: Byte 127 of the header should be the 8-bit sum of bytes ++ 0-126 of the header. The header should also have the ++ +3DOS magic number, but we know it does or we wouldn't ++ have got this far. ++ */ ++ ++ c1 = 0; ++ for (c1 = c = 0; c < 127; c++) c1 = ((c1 + zxfile[c]) & 0xFF); ++ if (c1 != zxfile[127]) zxError(bname, "Bad header checksum."); ++ ++ fclose(fp); ++ free(zxfile); ++ return 1; ++} ++ ++ ++ ++ ++ ++/*******************************************/ ++static int zxError(fname, st) ++ char *fname, *st; ++{ ++ SetISTR(ISTR_WARNING,"%s: %s", fname, st); ++ return 0; ++} ++ ++ ++/* Spectrum screen file header. The first 18 bytes are used in the magic ++ number test */ ++ ++byte ZXheader[128] = ++{ ++ 'P', 'L', 'U', 'S', '3', 'D', 'O', 'S', 26, /* Spectrum +3DOS file */ ++ 1, 0, /* Header type 1.0 */ ++ 128, 27, 0, 0, /* 7040 bytes */ ++ 3, /* Binary format */ ++ 0, 27, /* 6912 data bytes */ ++ 0, 64 /* load address 0x4000 */ ++}; ++ ++ ++ ++/* Get the Spectrum colour/bright byte (0-15) from a pixel */ ++ ++static int PointZX(pic, w, h, rmap, gmap, bmap, x, y) ++ byte *pic; ++ int w,h; ++ byte *rmap, *gmap, *bmap; ++ int x,y; ++{ ++ int index, r, g, b, zxc; ++ ++ /* If the picture is smaller than the screen, pad out the edges ++ with "bright black" - a colour not otherwise returned */ ++ ++ if (x >= w || y >= h) return 8; ++ ++ /* Get colour index */ ++ ++ index = pic[y*w + x]; ++ ++ /* Convert to rgb */ ++ ++ r = rmap[index]; ++ g = gmap[index]; ++ b = bmap[index]; ++ zxc = 0; ++ ++ /* Work out Spectrum colour by a simplistic "nearest colour" method */ ++ ++ if (b >= 160) zxc |= 1; /* Blue */ ++ if (r >= 160) zxc |= 2; /* Red */ ++ if (g >= 160) zxc |= 4; /* Green */ ++ if (r > 208 || g >= 208 || b >= 208) zxc |= 8; /* High intensity */ ++ ++ return zxc; ++} ++ ++ ++/* Work out what colours should be used in a cell */ ++ ++static void CellZX(pic, w, h, rmap, gmap, bmap, cx, cy, zxfile) ++ byte *pic; ++ int w,h; ++ byte *rmap, *gmap, *bmap; ++ int cx,cy; ++ byte *zxfile; ++{ ++ byte counts[16]; /* Count of no. of colours */ ++ int offset, ink, paper, n, m, x, y, x0, y0, di, dp; ++ ++ x0 = cx * 8; /* Convert from cell to pixel coords */ ++ y0 = cy * 8; ++ ++ for (n = 0; n < 16; n++) counts[n] = 0; /* Reset all counts */ ++ ++ /* Count no. of pixels of various colours */ ++ ++ for (y = y0; y < y0+8; y++) for (x = x0; x < x0+8; x++) ++ { ++ m = PointZX(pic, w, h, rmap, gmap, bmap, x, y); ++ ++ counts[m]++; ++ } ++ counts[8] = 0; /* Discard Bright Black (pixels not in the picture area) ++ */ ++ ++ /* Assign the most popular colour as ink */ ++ for (n = m = ink = 0; n < 16; n++) if (counts[n] > m) ++ { ++ ink = n; ++ m = counts[n]; ++ } ++ counts[ink] = 0; ++ ++ /* Assign the next most popular colour as paper */ ++ for (n = m = paper = 0; n < 16; n++) if (counts[n] > m) ++ { ++ paper = n; ++ m = counts[n]; ++ } ++ /* We have ink and paper. Set cell's attributes */ ++ ++ offset = cy*32 + cx + 0x1880; ++ ++ /* Set the high-intensity bit if ink is high-intensity */ ++ if (ink & 8) zxfile[offset] = 0x40; else zxfile[offset] = 0; ++ zxfile[offset] |= ((paper & 7) << 3); ++ zxfile[offset] |= (ink & 7); ++ ++ /* Plot the points */ ++ for (y = y0; y < y0+8; y++) ++ { ++ byte mask = 0x80; ++ ++ offset = (y >> 6) * 2048; ++ offset += (y & 7) * 256; ++ offset += (y & 0x38) * 4; ++ offset += (x0 >> 3); ++ ++ for (x = x0; x < x0+8; x++) ++ { ++ /* Work out whether the point should be plotted as ink or ++ paper */ ++ m = PointZX(pic, w, h, rmap, gmap, bmap, x, y); ++ ++ di = (ink & 7) - (m & 7); /* "Difference" from ink */ ++ dp = (paper & 7) - (m & 7); /* "Difference" from paper */ ++ ++ if (di < 0) di = -di; ++ if (dp < 0) dp = -dp; ++ ++ if (di < dp) /* Point is more like ink */ ++ zxfile[offset+128] |= mask; ++ ++ mask = (mask >> 1); ++ } ++ } ++ ++} ++ ++ ++ ++/*******************************************/ ++int WriteZX(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,comment) ++ FILE *fp; ++ byte *pic; ++ int ptype, w,h; ++ byte *rmap, *gmap, *bmap; ++ int numcols, colorstyle; ++ char *comment; ++{ ++ int rv, x, y; ++ byte *zxfile; ++ byte *pic8; ++ byte rtemp[256],gtemp[256],btemp[256]; ++ ++ /* To simplify matters, reduce 24-bit to 8-bit. Since the Spectrum ++ screen is 3.5-bit anyway, it doesn't make much difference */ ++ ++ if (ptype == PIC24) ++ { ++ pic8 = Conv24to8(pic, w, h, 256, rtemp,gtemp,btemp); ++ if (!pic8) FatalError("Unable to malloc in WriteZX()"); ++ rmap = rtemp; gmap = gtemp; bmap = btemp; numcols=256; ++ } ++ else pic8 = pic; ++ ++ ZXheader[127] = 0x71; /* The correct checksum. */ ++ ++ /* Create a memory image of the SCREEN$ */ ++ ++ zxfile = (byte *)malloc(7040); ++ if (!zxfile) FatalError("malloc failure in xvzx.c WriteZX"); ++ ++ memset(zxfile, 0, 7040); /* Reset all points to black */ ++ memcpy(zxfile, ZXheader, 128); /* Create +3DOS header */ ++ ++ /* Convert the image, character cell by character cell */ ++ for (y = 0; y < 24; y++) for (x = 0; x < 32; x++) ++ { ++ CellZX(pic8, w, h, rmap, gmap, bmap, x, y, zxfile); ++ } ++ rv = 0; ++ if (fwrite(zxfile, 1, 7040, fp) < 7040) rv = -1; ++ ++ if (ptype == PIC24) free(pic8); ++ free(zxfile); ++ ++ if (ferror(fp)) rv = -1; ++ ++ return rv; ++} ++ |