summaryrefslogtreecommitdiffstats
path: root/source/xap/xv/xv-3.10a-jumbo-enh-patch-20050501.txt
diff options
context:
space:
mode:
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.txt28167
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 000000000..d78b601a9
--- /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;
++}
++