slackware-current/source/xap/xv/xv-3.10a-jumbo-additions.diff
Patrick J Volkerding b76270bf9e Slackware 13.1
Wed May 19 08:58:23 UTC 2010
Slackware 13.1 x86_64 stable is released!
Lots of thanks are due -- see the RELEASE_NOTES and the rest of the
ChangeLog for credits.  The ISOs are on their way to replication,
a 6 CD-ROM 32-bit set and a dual-sided 32-bit/64-bit x86/x86_64 DVD.
We are taking pre-orders now at store.slackware.com, and offering
a discount if you sign up for a subscription.  Consider picking up
a copy to help support the project.  Thanks again to the Slackware
community for testing, contributing, and generally holding us to a
high level of quality.  :-)
Enjoy!
2018-05-31 22:43:05 +02:00

18743 lines
527 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff -u -r --new-file xv-3.10a.orig/README.jumbo xv-3.10a/README.jumbo
--- xv-3.10a.orig/README.jumbo 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/README.jumbo 2007-05-21 00:19:20.000000000 -0500
@@ -0,0 +1,559 @@
+This is the latest version of the XV jumbo patches I originally created in
+February 2000 (but never distributed) and eventually updated and released in
+May 2004, prompted by a discussion on LWN (http://lwn.net/Articles/76391/).
+Information about the patches, updates to the patches, and the patches
+themselves can all be found here:
+
+ http://pobox.com/~newt/greg_xv.html
+ http://freshmeat.net/projects/xvjumbopatches/
+
+(Use the "Subscribe to new releases" link on the latter page if you want to
+be notified of new versions automatically; trivial registration required.)
+
+These patches incorporate all of the fix- and enhancement-patches 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 (security-related and otherwise), plus quite a few from other
+people. They're still not fully complete, and it's probable 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, once every few years may be the best we can hope for....)
+
+Also be aware that several other people have had the same idea over the
+years. Ones I've found, more or less by accident, include:
+
+ - Landon Curt "chongo" Noll (http://www.isthe.com/chongo/)
+ http://www.isthe.com/chongo/src/xv-patch/
+ - 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>
+ 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>
+ 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>
+ 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/
+ - Kyoichiro Suda <sudakyo fat.coara.or.jp>
+ http://www.coara.or.jp/~sudakyo/XV_jp.html
+
+This is not an exhaustive list (e.g., J<>rgen Grahn also had one). 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, circa 2005. (As of 2007, they're
+distributed as a single monster-patch, and the "component patches" are now
+listed in the changelog section at the bottom of this file.) 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 the
+list, that would 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 and changelog
+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)
+ AS = Alexey Spiridonov (http://www-math.mit.edu/~lesha/)
+ AT = Anthony Thyssen (http://www.cit.gu.edu.au/~anthony/)
+ BR = Bruno Rohee (http://bruno.rohee.com/)
+ DAC = David A. Clunie (http://www.dclunie.com/xv-pcd.html)
+ EAJ = Erling A. Jacobsen (linuxcub email.dk)
+ EK = Egmont Koblinger (egmont users.sourceforge.net)
+ FG = Fabian Greffrath (fabian debian-unofficial.org)
+ GRR = Greg Roelofs (http://pobox.com/~newt/greg_contact.html)
+ GV = Guido Vollbeding (http://sylvana.net/guido/)
+ IM = IKEMOTO Masahiro (ikeyan airlab.cs.ritsumei.ac.jp)
+ JC = John Cooper (john.cooper third-harmonic.com)
+ JCE = John C. Elliott (http://www.seasip.demon.co.uk/ZX/zxdload.html)
+ JDB = John D. Baker (http://mylinuxisp.com/~jdbaker/)
+ JG = J<>rgen Grahn (jgrahn algonet.se)
+ 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)
+ JRK = James Roberts Kirkpatrick (uwyo.edu)
+ 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)
+ RAC = Ross Combs (rocombs cs.nmsu.edu)
+ RJH = Robin Humble (http://www.cita.utoronto.ca/~rjh/)
+ SB = Sean Borman (http://www.nd.edu/~sborman/software/xvwheelmouse.html)
+ SJT = TenThumbs (tenthumbs cybernex.net)
+ SBM = Scott B. Marovich (formerly marovich hpl.hp.com)
+ TA = Tim Adye (http://hepwww.rl.ac.uk/Adye/xv-psnewstyle.html)
+ TAR = Tim Ramsey (tar pobox.com)
+ 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 and wrote to
+him again in May 2005), unless you count Debian's redistribution permission
+(Daniel Kirchheimer, 5 Dec 2005). 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 try to fix 'em--eventually,
+anyway... ;-) )
+
+Greg Roelofs, 20070520
+http://pobox.com/~newt/greg_contact.html
+
+
+How to build
+------------
+
+The following assumes you, the user, already have the libtiff,[1] libjpeg,[2]
+libpng,[3] zlib,[4] and JasPer[5] libraries downloaded, patched (if necessary),
+compiled, and installed, not to mention a C compiler and the bzip2,[6] tar,[7]
+patch,[8] and make[9] utilities. You should also have downloaded the original
+XV 3.10a source distribution from the XV Downloads page[10] and be able to edit
+its Makefile and config.h files as indicated in the INSTALL file. (Editing
+the Makefile will also allow you to disable some of the third-party libraries
+if you wish.) Finally, you should know what a Unix(-style) command line is,
+where to find one, and how to wield it with abandon (or at least with adult
+supervision)--and preferably not as the root user until the "make install"
+step. (A filesystem is a terrible thing to waste.)
+
+ [1] http://www.remotesensing.org/libtiff/
+ [2] http://www.ijg.org/
+ [3] http://www.libpng.org/pub/png/libpng.html
+ [4] http://www.zlib.net/
+ [5] http://www.ece.uvic.ca/~mdadams/jasper/
+ [6] http://sources.redhat.com/bzip2/
+ [7] http://www.gnu.org/directory/devel/specific/tar.html
+ [8] http://www.gnu.org/directory/devel/specific/patch.html
+ [9] http://www.gnu.org/directory/devel/specific/make.html
+ [10] http://www.trilon.com/xv/downloads.html#src-distrib
+
++-------------------------------------------------------------------------+
+| |
+| BIG SCARY WARNING |
+| |
+| These patches work for Greg (and parts of them reportedly work for |
+| various other people), and so far Greg's CPU still computes and his |
+| hard disks haven't been wiped. But there's no guarantee that this |
+| will be the case for you! In particular, not every incorporated patch |
+| has been explicitly tested, nor has every possible subcase of the |
+| explicitly tested subset. (Read that again; it's grammatical.) Nor |
+| are these patches officially blessed by John Bradley in any way. In |
+| other words, if you use these patches, you do so at your own risk. |
+| (Greg doesn't believe there are any serious problems remaining, but |
+| then, what programmer ever does? Bugs happen.) |
+| |
++-------------------------------------------------------------------------+
+
+Assuming you have the prerequisites out of the way and aren't scared
+off by the Big Scary Warning, here's the build procedure:
+
+ tar xvzf xv-3.10a-jumbo-patches-20070520.tar.gz
+ (or: gzip -dc xv-3.10a-jumbo-patches-20070520.tar.gz | tar xvf - )
+
+ tar xvzf xv-3.10a.tar.gz
+
+ cd xv-3.10a
+
+ patch -p1 < ../xv-3.10a-jumbo-fix-enh-patch-20070520.txt
+
+ edit Makefile and config.h as directed in INSTALL file (in particular,
+ ensure paths to external libraries and header files are correct)
+
+ make
+
+ ./xv your_favorite_image your_other_favorite_image etc.
+
+If everything seems to be working to your satisfaction, go ahead and install:
+
+ make -n install (and double-check that things will be installed
+ where you want them to be)
+
+ become root if necessary (e.g., type su)
+
+ make install
+ (or: sudo make install)
+
+That wasn't so hard, was it?
+
+
+Summary of incorporated and unincorporated patches (through 20050501)
+---------------------------------------------------------------------
+(See the ChangeLog at the bottom for more recent incorporated patches.)
+
+fixes ((*) = listed on XV Downloads page, (f) = on ftp site only):
+
+20040516:
+ - grabpatch (*) [obsoleted by new-xvgrab.c below]
+ - vispatch (*)
+ - mp-tiff-patch (*) [technically an enhancement, but JHB says...]
+ - longname.patch (*) [*SECURITY*]
+ - xpm.patch (*)
+ - deepcolor.patch (*) [slightly modified for language conformance]
+ - gifpatch (*)
+ - exceed_grab.patch (*)
+ - xv-redhat6-readme.txt (*) [slightly modified for portability]
+ - beos.patch (*) [modified for portability]
+ - croppad.patch (f)
+ - epsfpatch (f)
+ - tiff1200.patch (*)
+ - gssafer.patch (*) [*SECURITY*]
+ - new-xvgrab.c (f) [includes grabpatch but not exceed_grab.patch]
+ - xcmap.diff (AD) [part of xv-3.10a-png-1.2d.tar.gz]
+ - fixes for huge number gcc -Wall warnings--including two bugs (GRR)
+ - fix for cleandir script when no makefile exists (GRR)
+ - *SECURITY* fix for gets() in vdcomp.c (GRR, LCN vdcomp-security.patch)
+ - *SECURITY* fix for getwd() on Linux (GRR, LCN Linux-compile.patch)
+ - fix for "no fuss" Linux compiles (LCN Linux-compile.patch)
+ - partial *SECURITY* fix for mktemp() in xv.c and xvdir.c (GRR)
+ (remaining instances in xv.c (2), xvimage.c, xvfits.c, xvpds.c, xvps.c, and
+ possibly xvtiff.c--most involve system())
+ - 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)
+ - fixes for gcc 3.3 -Wall warnings (GRR)
+ - fix for incorrect 16/24-bit display of xwd dumps (SJT)
+ - *SECURITY* fix for multiple input-validation bugs (OpenBSD/SuSE, Gentoo, GRR)
+ (this also completes the partial mktemp() security fix listed above)
+ - fix for (probable) 24-bit endianness bug in fixpix code (GRR)
+
+
+enhancements ((*) = listed on XV Downloads page, (<who>) = third-party):
+
+20040516:
+ - xv-3.10a.JPEG-patch (*)
+ (xv-3.10a.JPEG-patch.old differs only in ftp site listed in comments at top)
+ - xv-3.10a.TIFF-patch (*)
+ - xv-3.10a-png-1.2d.tar.gz (AL, AD) (*)
+ (xvjpeg.diff and xvtiff.diff ignored; xcmap.diff included in fixes)
+ - xvpng-1.2d-fix3.patch (GRR, SJT) (*)
+ - pdf.patch (*)
+ - windowid.patch + windowid.patch.readme (*)
+ - bmp32.patch (*)
+ - fixpix-20000610.tar.gz (GV)
+ (identical to 19961127 version except for README updates and new Win32 file)
+ [modified to be runtime-selectable via -/+fixpix option]
+ - browse-remember.patch (JZ)
+ - faster-smooth.patch (JZ)
+ - PAM support (GRR)
+ - PNG/GIF -ibg ("image background") transparency option (GRR)
+ (does not yet support TIFF, XPM or TGA)
+ - VersionInfo* in help screen (GRR)
+ - minor grammar/spelling fixes (GRR)
+ - floating-point support for -wait when USE_TICKS enabled (GRR)
+ - wheelmouse.patch (SB)
+ - freebsd-gravity-hints-patch (JR)
+ - xv-zx.patch (JCE)
+ - xv3.10a.wapbmp.patch (PSV)
+ - xv-3.10a-pcd.patch.20010708 (DAC)
+ - jp-ext-bzip2-1.1.patch
+ (from ftp://ftp.freebsd.org/pub/FreeBSD/ports/local-distfiles/shige/xv/)
+20050410:
+ - 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 (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:
+
+ - others from http://www.coara.or.jp/~sudakyo/XV_jp.html (some are duplicates):
+ -rw-r--r-- 4644 Mar 11 2004 xv-3.10a-directory.patch
+ -rw-r--r-- 462 Mar 11 2004 xv-3.10a-dirwkey.patch
+ -rw-r--r-- 688 Mar 11 2004 xv-3.10a-docdir.patch
+ -rw-r--r-- 11952 Mar 11 2004 xv-3.10a-download-test0.patch
+ -rw-r--r-- 41786 Mar 11 2004 xv-3.10a-download-test1.patch
+ -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-- 3423 Apr 24 2004 xv-3.10a-keyzoom.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-- 57092 Jul 9 2004 xv-3.10a-resolution.patch
+ -rw-r--r-- 4645 Apr 24 2004 xv-3.10a-selall.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-- 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-- 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
+
+ - xv-3.10a+jp-extension-rev5.3.3+FLmask.v2.1+png+misc.patch ["mask" support]
+
+ - xv-psnewstyle.patch (TA) [coming "soon"?]
+ - xv-3.10a.patch.linux (PBJ) [maybe use vdcomp.c changes?]
+ - xvxpm-anthony-thyssen.c (AT) ["slate grey" bug already gone?]
+ - xv-geoff-kuenning-iconsize-slideshow.patch [var. icons; full-screen slides]
+ - xv-scott-marovich-20070214-xvtiff.c.patch6.unified [TIFF CMYK support]
+
+ - stuff in xv/unsupt:
+ -rw-r--r-- 30527 Dec 22 1994 FITS.rite
+ -rw-r--r-- 49152 Dec 22 1994 FITS.tar
+ -rw-r--r-- 3753 Dec 22 1994 G3.patch1
+ -rw-r--r-- 24576 Dec 22 1994 G3.tar
+ -rw-r--r-- 1098 Dec 22 1994 INFO.cgm
+ -rw-r--r-- 1941 Dec 22 1994 README
+ -rwxr-xr-x 1059 Dec 22 1994 getweather
+ -rwxr-xr-x 2186 Dec 22 1994 getweather.ksh
+ -rw-r--r-- 856 Dec 22 1994 twm.fix
+ -rw-r--r-- 844 Dec 22 1994 vargs.c
+ -rw-r--r-- 47626 Dec 22 1994 vis
+ -rw-r--r-- 21097 Dec 22 1994 xscm
+
+
+
+not finished (and/or even started ;-) ):
+
+ - fix xvpng.c not to use direct struct access
+ - (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 deficiencies
+ (positioning fixed 20070104 by Ross Combs; would like select/cut/paste, too)
+ - fix for .ppm.gz "disk leak" [can't reproduce...already fixed?]
+ (maybe occurs only if filesystem is already nearly full? bad .gz?)
+
+ - transparency support for TIFF, XPM and TGA images
+ - support for tiled background image (with transparent foreground image)
+ - MNG/JNG support
+ - SVG support
+
+
+ChangeLog
+---------
+
+ 20000220
+ original pair of jumbo patches, comprising perhaps 16 fix-patches and a
+ dozen enhancement-patches; never publicly released
+
+ 20040516
+ first public release, incorporating 25 fix-patches and 21 enhancement-
+ patches
+
+ 20040523
+ minor fix to xvctrl.c to support registered versions (GRR warnings-patch
+ was slightly overzealous); switched to tarball packaging
+
+ 20040531
+ fixed undefined CLK_TCK with gcc -ansi (enh/USE_TICKS option); made
+ libjpeg, libtiff, libpng and zlib sections of makefile more consistent
+ (enh)
+
+ 20040606
+ added freshmeat link, build instructions, and changelog to jumbo README
+ (this file)
+
+ 20050213
+ increased max number of files from 4096 to 32768 (enh)
+
+ 20050320-20050410
+ fixed two very long-standing YCbCr bugs in TIFF decoder (fix);
+ provisionally fixed bug in TIFF decoder for contiguous tiled TIFFs with
+ bottom-* orientation (fix/USE_TILED_TIFF_BOTLEFT_FIX option); fixed new
+ gcc 3.3 warnings (fix); fixed incorrect 16/24-bit display of xwd dumps
+ (fix); fixed multiple input-validation bugs (potential heap overflows)
+ and mktemp() dependencies (*SECURITY* fixes: CAN-2004-1725, CAN-2004-
+ 1726, CAN-2005-0665, CERT VU#622622, and others); added support for 16-
+ and 32-bit BMPs using bitfields "compression" (enh); fixed probable byte-
+ 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)
+
+ 20050528
+ conditionally added missing alloca.h to xvpcd.c (required if alloca() is
+ a macro and alloca.h not included in stdlib.h, for example); fixed bogus
+ __S_IWRITE introduced in 20050501 release; fixed Makefile "install" target
+ (mkdir, chmod); fixed bug in MUST macro in xvwbmp.c; fixed prototype
+ warnings in xvevent.c, xvpcd.c (JRK, GRR)
+ - xv-3.10a-jimkirk-fixes.patch
+
+ 20050630
+ fixed broken mkdir(.xvpics) introduced in 20050501 release (RJH, GRR);
+ tweaked GUNZIP config for OpenBSD (GRR)
+ - xv-3.10a-xvpics-mkdir-fix.patch
+
+ 20051014
+ fixed longstanding xvevent.c typo (wasJpegUp -> wasPngUp) that caused build
+ failure if no JPEG support (TAR)
+
+ 20051019
+ fixed Darwin (Mac OS X) build error in xv.h and vdcomp.c due to lack of
+ malloc.h (JDB)
+
+ 20070210
+ fixed minor grammos (GRR); promoted PNG to first position, demoted GIF to
+ third (GRR); changed internal type of default image to PNG (GRR); increased
+ max files again, to 65536 (GRR)
+
+ 20070310
+ incorporated JPEG-2000 patch (SBM, GRR); added manual fax options for
+ unrecognized G3 images (SBM); relaxed 30-byte minimum file size (SBM)
+ - http://www.ece.uvic.ca/~mdadams/jasper/software/xv-patches
+
+ 20070318
+ incorporated 16bps raw (binary) PPM patch (define ASSUME_RAW_PPM_LSB_FIRST
+ for old behavior) (RAC, GRR); updated format list, web sites in xv man page
+ (GRR); fixed Makefile "install" target to create any necessary directories
+ (RAC, GRR); fixed GIF decoder bug (sizes of global, local color tables
+ different) (GRR)
+ - xv-ross-combs-ppm-16bps-rawbits.patch
+
+ 20070325
+ fixed invalid gamma assumption in PNG decoder (=> progressive color changes
+ over load/save cycles) (GRR)
+
+ 20070328
+ fixed animated-GIF /tmp/xvpgXXXXXX droppings (GRR)
+
+ 20070331
+ fixed PNG duplicate-palette-entries bug (GRR)
+
+ 20070415
+ incorporated EXIF-preserve patch (GHK); added missing JP2/JPC VS bits code
+ (GRR); added extended-warning options to CCOPTS (RAC); added "const" to
+ huge number of function args (RAC, GRR); made more effectively static
+ functions officially static (RAC); added mouse-clickability (but not
+ selectability) to text-entry fields (RAC); fixed window positioning (race
+ conditions?) under some virtual window managers (e.g., tvtwm) (RAC);
+ removed explicit paths for external (de)compressors (GRR, RAC)
+ - xv-geoff-kuenning-jpeg-exif-preserve.patch
+ - xv-ross-combs-20070104.diff
+
+ 20070422
+ incorporated function-key-scripts patch (see contrib/fnkey-scripts) (AS);
+ fixed man-page-section extensions ("1", not "l" or "1X") (FG); switched to
+ more sensible install paths for docs (FG); added Fedora Core build script
+ (see contrib/fedora) (JC); fixed VS to switch from move-mode to copy-mode
+ if source dir is read-only (EAJ); extended VS incremental-search mode (EAJ)
+ - xv-alexey-spiridonov-20070116-fnkey-scripts.tar.bz2
+ - xv-fabian-greffrath-20070215-debian-04-manpages.dpatch
+ - xv-fabian-greffrath-20070215-debian-03-makefiles.dpatch
+ - xv-john-cooper-Build-FC5-script.sh
+ - xv-erling-jacobsen-20060617-incr-search.patch
+
+ 20070428
+ modified install to include README.jumbo in docs (GRR); incorporated PNG
+ no-stdio patch (SBM); fixed XWD endianness support, improved performance
+ (replaces SJT 16/24-bit fix) (SBM)
+ - xv-scott-marovich-20070214-xvpng.diff
+ - xv-scott-marovich-20070214-xvxwd.c.patch
+
+ 20070506
+ added JPEG CMYK support (SBM); fixed TIFF (and others?) /tmp/xvpgXXXXXX
+ droppings (GRR); added VS clipboard support (JG)
+ - xv-scott-marovich-20070214-xvjpeg.c.patch
+ - xv-jurgen-grahn-20051127-schnauzer-clip.patch
+
+ 20070512
+ inverted handling of malloc.h header file to require NEED_MALLOC_H macro
+ for those few systems that actually need it (GRR)
+
+ 20070513
+ fixed GCC 4.1.x warnings (GRR); next round of const cleanup (GRR); fixed
+ minor TIFF memleak (GRR)
+
+ 20070514
+ fixed TIFF YCbCr reference black/white levels (SBM); added option to use
+ libjpeg YCbCr-to-RGB conversion for TIFF images (SBM, GRR)
+ - xv-scott-marovich-20070214-xvtiff.c.patch2.unified
+ - xv-scott-marovich-20070214-xvtiff.c.patch3.unified
+
+ 20070519
+ fixed handling of multi-page JPEG-compressed TIFFs (old or new) (SBM);
+ added TIFF YCbCr separated-color-plane support (may require libtiff
+ patch(es) to tif_ojpeg.c and/or tif_jpeg.c) (SBM)
+ - xv-scott-marovich-20070214-xvtiff.c.patch4.unified
+ - xv-scott-marovich-20070214-xvtiff.c.patch5.unified
+
+ 20070520
+ updated README.jumbo
diff -u -r --new-file xv-3.10a.orig/README.pcd xv-3.10a/README.pcd
--- xv-3.10a.orig/README.pcd 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/README.pcd 2001-07-08 13:21:19.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_bzip2 xv-3.10a/bits/br_bzip2
--- xv-3.10a.orig/bits/br_bzip2 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_bzip2 1998-04-12 21:23:39.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_jp2 xv-3.10a/bits/br_jp2
--- xv-3.10a.orig/bits/br_jp2 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_jp2 2005-05-09 00:00:27.000000000 -0500
@@ -0,0 +1,27 @@
+#define br_jp2_width 48
+#define br_jp2_height 48
+static unsigned char br_jp2_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, 0xfb, 0xf1, 0x01, 0x02,
+ 0x20, 0x00, 0xfb, 0xfb, 0x03, 0x02, 0x20, 0x00, 0x1b, 0x1b, 0x03, 0x02,
+ 0x20, 0x00, 0x1b, 0x1b, 0x00, 0x02, 0x20, 0x00, 0x1b, 0x1b, 0x00, 0x02,
+ 0x20, 0x00, 0x9b, 0x1b, 0x00, 0x02, 0x20, 0x00, 0xfb, 0x19, 0x00, 0x02,
+ 0x20, 0x00, 0xfb, 0x18, 0x00, 0x02, 0x20, 0x18, 0x1b, 0x18, 0x00, 0x02,
+ 0x20, 0x18, 0x1b, 0x18, 0x00, 0x02, 0x20, 0xb8, 0x1b, 0x18, 0x03, 0x02,
+ 0x20, 0xf0, 0x19, 0xf8, 0x03, 0x02, 0x20, 0xe0, 0x18, 0xf0, 0x01, 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 -u -r --new-file xv-3.10a.orig/bits/br_jpc xv-3.10a/bits/br_jpc
--- xv-3.10a.orig/bits/br_jpc 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_jpc 2005-05-09 00:00:27.000000000 -0500
@@ -0,0 +1,27 @@
+#define br_jpc_width 48
+#define br_jpc_height 48
+static unsigned char br_jpc_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, 0xfb, 0xf1, 0x01, 0x02,
+ 0x20, 0x00, 0xfb, 0xfb, 0x03, 0x02, 0x20, 0x00, 0x1b, 0x1b, 0x03, 0x02,
+ 0x20, 0x00, 0x1b, 0x03, 0x03, 0x02, 0x20, 0x00, 0x1b, 0x03, 0x03, 0x02,
+ 0x20, 0x00, 0x9b, 0x83, 0x01, 0x02, 0x20, 0x00, 0xfb, 0xc1, 0x01, 0x02,
+ 0x20, 0x00, 0xfb, 0xe0, 0x00, 0x02, 0x20, 0x18, 0x1b, 0x70, 0x00, 0x02,
+ 0x20, 0x18, 0x1b, 0x38, 0x00, 0x02, 0x20, 0xb8, 0x1b, 0x18, 0x00, 0x02,
+ 0x20, 0xf0, 0x19, 0xf8, 0x03, 0x02, 0x20, 0xe0, 0x18, 0xf8, 0x03, 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 -u -r --new-file xv-3.10a.orig/bits/br_mag xv-3.10a/bits/br_mag
--- xv-3.10a.orig/bits/br_mag 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_mag 2005-04-17 16:04:22.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_maki xv-3.10a/bits/br_maki
--- xv-3.10a.orig/bits/br_maki 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_maki 2005-04-17 16:04:22.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_mgcsfx xv-3.10a/bits/br_mgcsfx
--- xv-3.10a.orig/bits/br_mgcsfx 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_mgcsfx 2005-04-17 16:04:22.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_pcd xv-3.10a/bits/br_pcd
--- xv-3.10a.orig/bits/br_pcd 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_pcd 1995-06-15 23:31:53.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_pi xv-3.10a/bits/br_pi
--- xv-3.10a.orig/bits/br_pi 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_pi 2005-04-17 16:04:22.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_pic xv-3.10a/bits/br_pic
--- xv-3.10a.orig/bits/br_pic 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_pic 2005-04-17 16:04:22.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_pic2 xv-3.10a/bits/br_pic2
--- xv-3.10a.orig/bits/br_pic2 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_pic2 2005-04-17 16:04:22.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_png xv-3.10a/bits/br_png
--- xv-3.10a.orig/bits/br_png 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_png 1996-06-13 16:32:08.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/bits/br_zx xv-3.10a/bits/br_zx
--- xv-3.10a.orig/bits/br_zx 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/bits/br_zx 1998-08-06 15:00:03.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/contrib/fedora/Build-FC5 xv-3.10a/contrib/fedora/Build-FC5
--- xv-3.10a.orig/contrib/fedora/Build-FC5 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/contrib/fedora/Build-FC5 2006-06-01 10:12:47.000000000 -0500
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# prep and build XV for FC5
+#
+# adapted from Slackware 10.2 -- john.cooper@third-harmonic.com
+#
+
+if [ ${1}foo == "__LOGGED__foo" ]; then
+ shift
+else
+ for i in `seq 0 9`
+ do
+ if [ -e ${0}.log.$((9-i)) ]; then
+ mv ${0}.log.$((9-i)) ${0}.log.$((9-i+1))
+ fi
+ done
+
+ exec $0 __LOGGED__ $@ 2>&1 | tee $BUILDDIR/$0.log.0
+ exit $?
+fi
+
+SOURCE=`pwd`
+if [ "$BUILD" = "" ]; then
+ BUILD=./build
+fi
+
+if [ ! -d $BUILD ]; then
+ mkdir -p $BUILD
+fi
+
+PFLAGS="--verbose --backup --suffix=.orig"
+
+function bail()
+ {
+ echo "$0: failed $1"
+ exit 1
+ }
+
+cd $BUILD
+rm -rf xv-3.10
+tar xzvf $SOURCE/xv-3.10.tar.gz
+cd xv-3.10
+zcat $SOURCE/xv-3.10a.patch.gz | patch -p0 $PFLAGS || \
+ bail $SOURCE/xv-3.10a.patch.gz
+bzcat $SOURCE/xv-3.10a-jumbo-fix-patch-20050410.txt.bz2 | patch -p1 $PFLAGS || \
+ bail $SOURCE/xv-3.10a-jumbo-fix-patch-20050410.txt.bz2
+bzcat $SOURCE/xv-3.10a-jumbo-enh-patch-20050501.txt.bz2 | patch -p1 $PFLAGS || \
+ bail $SOURCE/xv-3.10a-jumbo-enh-patch-20050501.txt.bz2
+zcat $SOURCE/xv.prefix.diff.gz | patch -p1 $PFLAGS || \
+ bail $SOURCE/xv.prefix.diff.gz
+make -f Makefile.std || bail make
+strip --strip-unneeded bggen vdcomp xcmap xv xvpictoppm || bail strip
+
+exit $?
+
+# vi:set ts=4:
diff -u -r --new-file xv-3.10a.orig/contrib/fedora/README xv-3.10a/contrib/fedora/README
--- xv-3.10a.orig/contrib/fedora/README 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/contrib/fedora/README 2006-06-01 10:12:47.000000000 -0500
@@ -0,0 +1,16 @@
+Greg,
+ After winding up in dark lonely places trying to
+get xv-3.10a to build on FC5 I suspected I was missing
+something. Then I happened on your patch manifest
+in Slackware 10.2.
+
+I bandsawed the script a bit to use in propagating XV
+to a handful of personal FC5 machines. Attached for
+reference.
+
+Thanks for your effort!
+
+-john
+
+--
+john.cooper@third-harmonic.com
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/README xv-3.10a/contrib/fnkey-scripts/README
--- xv-3.10a.orig/contrib/fnkey-scripts/README 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/contrib/fnkey-scripts/README 2007-01-16 02:41:51.000000000 -0600
@@ -0,0 +1,111 @@
+-- License and Disclaimer --
+
+This patch & script package was written by Alexey Spiridonov, and is
+licensed under the GNU GPLv2. There is NO WARRANTY.
+
+XV is copyrighted by John Bradley.
+
+-- What is this? --
+
+This is a small patch for XV that allows you to run scripts by pressing
+a key from F1 through F12 (or more, just change 12 to your number in the
+patch file).
+
+The patch enables a number of useful features. Here is a my set-up:
+
+F1: Losslessly rotate JPEG 90 degrees to the right.
+F2: Losslessly rotate JPEG 90 degrees to the left.
+
+F3: Print the current selection rectangle (on the terminal where xv was
+ launched). This is useful for quickly recording a bunch of positions in
+ an image. Use case:
+ I'm annotating face positions.
+ 1) Select Joe in picture, hit F3, type "Joe" in the terminal.
+ 2) Select Jane in the picture, ...
+ ...
+ n) Copy the text visible in the terminal, and paste it into the
+ JPEG comment.
+ Of course, i would write a more convenient script if I annotated faces
+ with any any frequency.
+
+F4: Edit JPEG comment (I use it for annotations/tags).
+
+F5: Log a 'losslessly rotate right' command for batch processing. This
+ writes the rotation command for the current file into a shell script
+ somewhere ("~/photos/bin/rotscript" by default). This is great for
+ slower computers because you don't have to wait for each image to
+ rotate; instead, you just rotate them all at once by running the
+ resulting script.
+F6: Log a 'losslessly rotate left' batch command.
+
+F8: Crop image on disk, but back-up the uncropped version. You can make
+ a succession of crops this way, with a backup made at every step.
+ This wastes disk space, so be sure to clean up once you get a crop you
+ like.
+F7: Undo the last crop done on this image. This can be repeated until you're
+ back at the original.
+
+-- Installation --
+
+I'll tell you how to get the set-up I described above. Of course, you can
+customize it to your heart's content.
+
+(( 1 ))
+
+Go to:
+
+ http://www.sonic.net/~roelofs/greg_xv.html
+
+and follow the XV install instructions there. If you are okay with
+reading shell scripts, you might also give this a shot:
+
+ http://sources.gentoo.org/viewcvs.py/*checkout*/gentoo-x86/media-gfx/xv/xv-3.10a-r12.ebuild
+
+When you're ready to type "make install", do the following to apply my patch:
+
+ $ cd WHEREVER_YOU_COMPILED_XV
+ $ patch -p1 --dry-run < PATH/TO/xv-3.10a-fkey-command-patch.greg-xv
+
+Hopefully, the above command won't complain; if it does, Greg Roelofs
+probably changed his patchset, and my patch has become out of date -- let me
+know. If that went well, run:
+
+ $ patch -p1 < PATH/TO/xv-3.10a-fkey-command-patch.greg-xv
+
+Now, simply recompile and install as described in the other instructions.
+
+(( 2 ))
+
+Copy 'jpegcrop.sh', 'jpegeditcom.sh', 'jpegundocrop.sh', 'jpegrot.sh',
+'jpeglogrot.sh' to some convenient directory.
+
+Suggestions: ~/photos/bin, /usr/local/bin, etc...
+
+Edit 'jpeglogrot.sh' and 'jpegeditcom.sh'. In the former, you need to
+customize the path to 'jpegrot.sh'. In the latter, you should make set
+your favorite editor. The spots to customize are marked as such.
+
+(( 3 ))
+
+Open .Xdefaults in your favorite text editor, and paste the following lines
+there:
+
+xv.F1command: ~/photos/bin/jpegrot.sh 90 %s
+xv.F2command: ~/photos/bin/jpegrot.sh 270 %s
+xv.F3command: @echo "The selection rect for '%s' is at (%d, %d) of size %dx%d."
+xv.F4command: @~/photos/bin/jpegeditcom.sh %s &
+xv.F5command: @~/photos/bin/jpeglogrot.sh 90 %s
+xv.F6command: @~/photos/bin/jpeglogrot.sh 270 %s
+xv.F7command: ~/photos/bin/jpegundocrop.sh %s
+xv.F8command: ~/photos/bin/jpegcrop.sh %s %d %d %d %d
+
+Change '~/photos/bin/' to the directory you chose in (( 2 )). In case you're
+wondering what the '@' symbol means, it tells XV not to reload the file
+after running this command. The default is to reload the file.
+
+-- Apologies --
+
+I didn't get a chance to run through the above instructions and check
+that they work. I know they're right in spirit, but I might've made a typo
+or two. Even if it's obvious to you, would you please let me know by writing
+to lesha at mit dot edu?
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpegcrop.sh xv-3.10a/contrib/fnkey-scripts/jpegcrop.sh
--- xv-3.10a.orig/contrib/fnkey-scripts/jpegcrop.sh 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/contrib/fnkey-scripts/jpegcrop.sh 2006-03-11 21:30:03.000000000 -0600
@@ -0,0 +1,33 @@
+#!/bin/bash
+FILE=$1
+WIDTH=$4
+HEIGHT=$5
+XPOS=$2
+YPOS=$3
+if [[ $XPOS -lt 0 ]]; then
+ echo "Negative x position $XPOS converted to zero, width adjusted."
+ WIDTH=$((WIDTH+XPOS))
+ XPOS=0
+fi
+if [[ $YPOS -lt 0 ]]; then
+ echo "Negative y position $YPOS converted to zero, height adjusted."
+ HEIGHT=$((HEIGHT+YPOS))
+ YPOS=0
+fi
+if [[ $(($WIDTH+$HEIGHT)) == 0 ]]; then
+ echo "Refusing to crop $FILE with an empty rectangle."
+ exit 1
+fi
+
+TMPFILE=`mktemp $FILE.tmp-jpeg-rot-XXXXXXXX`
+if jpegtran -optimize -progressive -crop ${WIDTH}x${HEIGHT}+${XPOS}+${YPOS} \
+ -copy all $FILE > $TMPFILE; then
+ COUNT=`echo $FILE-uncropped | wc -c`
+ NEXT=$((`ls $FILE-uncropped* | cut -b $COUNT- | grep '^[0-9]*$' \
+ | sed 's/^0*/'/ | sort -n | tail -n 1`+1))
+ # the targets shouldn't exist, but -i just in case
+ mv -i $FILE $FILE-uncropped$NEXT
+ mv -i $TMPFILE $FILE
+else
+ rm $TMPFILE
+fi
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpegeditcom.sh xv-3.10a/contrib/fnkey-scripts/jpegeditcom.sh
--- xv-3.10a.orig/contrib/fnkey-scripts/jpegeditcom.sh 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/contrib/fnkey-scripts/jpegeditcom.sh 2007-01-16 00:23:04.000000000 -0600
@@ -0,0 +1,12 @@
+#!/bin/bash
+CFILE=`mktemp $1.tmp-jpeg-comments-XXXXXXXX`
+TMPFILE=`mktemp $1.tmp-jpeg-XXXXXXXX`
+rdjpgcom $1 > $CFILE
+INITIAL=`md5sum $CFILE`
+xterm -e "$EDITOR" "$CFILE" # customize your editor here
+MODIFIED=`md5sum $CFILE`
+if [[ "$INITIAL" != "$MODIFIED" ]]; then
+ mv $1 $TMPFILE
+ wrjpgcom -replace -cfile $CFILE $TMPFILE > $1
+fi
+rm $TMPFILE $CFILE $CFILE~
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpeglogrot.sh xv-3.10a/contrib/fnkey-scripts/jpeglogrot.sh
--- xv-3.10a.orig/contrib/fnkey-scripts/jpeglogrot.sh 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/contrib/fnkey-scripts/jpeglogrot.sh 2007-01-16 00:55:18.000000000 -0600
@@ -0,0 +1,10 @@
+#!/bin/bash
+curdir="`pwd`"
+LOG=~/photos/bin/rotscript # customize your install dir here
+if [[ ! -e "$LOG" ]]; then
+ echo '#!/bin/bash' >> "$LOG"
+ chmod u+x "$LOG"
+fi
+echo "# following entry made on `date`" >> "$LOG"
+# also customize the following line
+echo ~/photos/bin/jpegrot \""$1"\" \""$curdir/$2"\" >> "$LOG"
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpegrot.sh xv-3.10a/contrib/fnkey-scripts/jpegrot.sh
--- xv-3.10a.orig/contrib/fnkey-scripts/jpegrot.sh 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/contrib/fnkey-scripts/jpegrot.sh 2006-07-18 23:10:43.000000000 -0500
@@ -0,0 +1,7 @@
+#!/bin/bash
+TMPFILE="`mktemp "$2".tmp-jpeg-rot-XXXXXXXX`"
+if jpegtran -perfect -optimize -progressive -rotate "$1" -copy all "$2" > "$TMPFILE"; then
+ mv "$TMPFILE" "$2"
+else
+ rm "$TMPFILE"
+fi
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpegundocrop.sh xv-3.10a/contrib/fnkey-scripts/jpegundocrop.sh
--- xv-3.10a.orig/contrib/fnkey-scripts/jpegundocrop.sh 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/contrib/fnkey-scripts/jpegundocrop.sh 2006-03-11 21:30:04.000000000 -0600
@@ -0,0 +1,8 @@
+#!/bin/bash
+FILE=$1
+COUNT=`echo $FILE-uncropped | wc -c`
+LATEST=$((`ls $FILE-uncropped* | cut -b $COUNT- | grep '^[0-9]*$' \
+ | sed 's/^0*/'/ | sort -n | tail -n 1`))
+if [[ -f $FILE-uncropped$LATEST ]]; then
+ mv $FILE-uncropped$LATEST $FILE
+fi
diff -u -r --new-file xv-3.10a.orig/tiff/RANLIB.sh xv-3.10a/tiff/RANLIB.sh
--- xv-3.10a.orig/tiff/RANLIB.sh 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/tiff/RANLIB.sh 2004-05-11 01:31:38.000000000 -0500
@@ -0,0 +1,22 @@
+#!/bin/sh -f
+#
+# tests to see if the program 'ranlib' exists. If it does, runs ranlib on
+# the first argument (a library name). Otherwise, does nothing, and returns
+#
+# written by John Bradley for the XV 3.00 release
+# thanks to John Hagan for shell-script hackery
+#
+
+echo "executing 'ranlib $1'..."
+
+# Is there a ranlib? Let's try and then suffer the consequences...
+ranlib $1 >& /dev/null
+
+if [ $? -ne 0 ]; then
+ echo "There doesn't seem to be a ranlib on this system..."
+ echo "Don't worry about it."
+fi
+
+echo ""
+echo ""
+
diff -u -r --new-file xv-3.10a.orig/xv_mgcsfx.sample xv-3.10a/xv_mgcsfx.sample
--- xv-3.10a.orig/xv_mgcsfx.sample 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xv_mgcsfx.sample 2005-04-17 16:04:22.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvhips.c xv-3.10a/xvhips.c
--- xv-3.10a.orig/xvhips.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvhips.c 2005-05-01 01:49:14.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvhips.h xv-3.10a/xvhips.h
--- xv-3.10a.orig/xvhips.h 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvhips.h 2005-04-25 10:34:14.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvjp2k.c xv-3.10a/xvjp2k.c
--- xv-3.10a.orig/xvjp2k.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvjp2k.c 2007-05-13 20:04:37.000000000 -0500
@@ -0,0 +1,1326 @@
+/*
+ * xvjp2k.c - I/O subroutines for JPEG 2000 format pictures
+ *
+ * This module is a "shim" between XV and a JPEG 2000 CODEC in the open-source
+ * JasPer Library created by Michael D. Adams; for more information, see the URL
+ * "http://www.ece.uvic.ca/~mdadams/jasper". We don't use most of the other
+ * facilities in this library, so it's better to link XV with a UNIX "archive"
+ * representation of it, not a DLL.
+ *
+ * JPEG 2000 files can be represented in either of two general ways: The
+ * simplest representation is a "code stream", which often has a ".jpc" file
+ * name suffix and is organized much like a classical JPEG file, except that
+ * unfortunately, JPEG 2000 code streams indicate the no. of colors in an image
+ * but no longer give any clues about its color space (e.g., RGB or YCbCr).
+ * Instead, there is now a semantically higher-level representation, which often
+ * has a ".jp2" file name suffix and encapsulates a "code stream" with (possibly
+ * a lot of) color-space information, optionally including things like ICC
+ * correction tables.
+ *
+ * Compared to the IJG JPEG Library used in file "xvjpeg.c", one must solve
+ * several problems for color images when marrying JasPer to XV.
+ *
+ * 1. JPEG 2000 files can represent a wide range of image sizes, resolutions,
+ * and color spaces, not all of which can be easily rendered "as is" on a
+ * normal "X Windows" display, so we must carefully check a decoded image's
+ * parameters in order to reject anything that we can't handle gracefully.
+ *
+ * 2. JasPer prefers to decode/encode images using color-plane "slices", instead
+ * of interleaved pixels needed by "X Windows", so we must (de)interleave
+ * copies of the image buffer here.
+ *
+ * XXX Things to do:
+ *
+ * 1. In "LoadJP{2,C}()" try to handle the "quick" option, which requests
+ * faster loading of a reduced-size image for the visual schnauzer. The
+ * schnauzer's icon size is currently 80x60, so the old "xvjpeg.c" module tries
+ * to produce a 2X (160x120) image. Can we do the same?
+ *
+ * 2. In "StoreJP2K()", JasPer Library Version 1.701 apparently has no API to
+ * let the XV global "picComments" string be inserted in a JPEG 2000 comment
+ * record. If the library ever gets fixed, enhance our code accordingly.
+ *
+ * --Scott Marovich <marovich@hpl.hp.com>, Hewlett-Packard Laboratories,
+ * January 2005.
+ */
+#include "copyright.h"
+
+#define NEEDSARGS
+#include "xv.h"
+
+#ifdef HAVE_JP2K
+
+#include <jasper/jasper.h>
+/* missing prototype in 1.701.0, sigh: */
+jas_stream_t *jas_stream_freopen PARM((const char *, const char *, FILE *));
+
+static const char *fbasename, /* File's base name, for error/warning msgs */
+ bad_samp[] = "%s: can't read %d-plane %s file!",
+ fmode[] = "rb",
+ full_msg[] = "%s %s. (%ld bytes)",
+ jp2_kind[] = "JP2",
+ jpc_kind[] = "JPEG 2000",
+ load_msg[] = "Loading %dx%d %s %s (%ld bytes)...",
+ no_mem[] = "%s: can't read %s file - out of memory",
+ pixel_size[] = "%s: can't display %d-bit pixels!",
+ shrt_msg[] = "%dx%d %s %s. ",
+ truncated[] = "%s: Unexpected end of %s file",
+ read_err[] = "%s: I/O error reading %s file",
+ bad_dims[] = "%s: error in JPEG-2000 header (bad image size)";
+
+/* We only want to override the JasPer Library's "jas_eprintf()" subroutine in
+ order to make it a "wrapper" around XV's own error-reporting subroutine, but
+ because of the way the former is currently packaged in JasPer Library Version
+ 1.701, we must override everything else packaged in the "jas_debug.o" module
+ with it, otherwise we get "duplicate definition" messages from the linker.
+*/
+int jas_getdbglevel(void) {return 0;}
+int jas_setdbglevel(int n) {return 0;}
+int jas_memdump(FILE *fp,void *data,size_t len) {return 0;}
+
+int jas_eprintf(const char *fmt,...) /* Handle JasPer Library message */
+{
+ static char error[] = "error: ", warning[]= "warning: ";
+ va_list ap;
+ int kind = ISTR_WARNING;
+ char buffer[512];
+ register char *p;
+
+ /* Unlike the IJG JPEG Library, the JasPer Library current has no graceful way
+ for an application (= us!) to intercept its diagnostic messages and output
+ them using our own subroutines, so this ugly replacement for its output
+ subroutine will have to suffice. At Version 1.701, lthough the library's
+ own "jas_eprintf()" is a varargs subroutine, all calls currently pass just
+ 1 string with a Line Feed at the end and no "printf(3C)" arguments. Most
+ strings begin with "error: " or "warning: ", although a few have neither.
+ We try to translate these into the format preferred by XV, trimming any
+ trailing Line Feed character (ugh!).
+ */
+ va_start(ap, fmt);
+ vsnprintf(p = buffer,512,fmt,ap);
+ va_end(ap);
+ while (*p++);
+ if (p[-2] == '\n') p[-2] = '\0';
+ p = buffer;
+ if (strncmp(p,error,sizeof error) == 0) /* "error: ... " */
+ {
+ kind = ISTR_WARNING;
+ p += sizeof error;
+ }
+ else /* "warning: ... " */
+ if (strncmp(p,warning,sizeof warning) == 0)
+ {
+ kind = ISTR_INFO;
+ p += sizeof warning;
+ };
+ SetISTR(kind,"%s: %s",fbasename,p);
+ return strlen(fmt);
+}
+
+static char *SetBuf(FILE *f)
+{
+ char *buf;
+ register char *p;
+
+ /* JPEG 2000 image files are apt to be large, but the buffer size allocated by
+ most implementations of the "C" Standard I/O Library is still ridiculously
+ small, typically 1 KB. We want to allocate a much larger buffer for higher
+ I/O efficiency, but the details are unfortunately a bit platform-specific.
+ Under UNIX systems with virtual memory, we want to encourage its internal
+ "physio()" subroutine by making the buffer an integral number of pages,
+ aligned on a page-multiple memory address boundary. Under HP-UX 11.1+ and
+ perhaps other operating-systems, a Standard I/O buffer is preceded by a
+ header whose size must also be taken into account.
+ */
+# ifndef IOBUFSIZ
+# define IOBUFSIZ 65536
+# endif /* IOBUFSIZ */
+# ifdef __hpux
+# define OVERHEAD sizeof(mbstate_t)
+# endif /* __hpux */
+# ifndef OVERHEAD
+# define OVERHEAD 0
+# endif /* OVERHEAD */
+
+# ifdef NBPG
+ if (!(buf = p = malloc(NBPG+OVERHEAD+IOBUFSIZ))) return 0;
+ p = (char *)((unsigned long)p+NBPG-1 & ~(NBPG-1));
+ p -= OVERHEAD;
+# else /* not NBPG */
+ if (!(buf = p = malloc(OVERHEAD+IOBUFSIZ))) return 0;
+ p += OVERHEAD;
+# endif /* NBPG */
+ setvbuf(f,p,_IOFBF,OVERHEAD+IOBUFSIZ);
+ return buf;
+# undef OVERHEAD
+# undef IOBUFSIZ
+}
+
+int LoadJPC(char *fname,register PICINFO *pinfo,int quick)
+{
+ jas_image_t *img;
+ jas_stream_t *str;
+ FILE *fp;
+ char *iobuf;
+ const char *s;
+ unsigned long filesize;
+ long w, h, npixels, bufsize;
+ int ok = 0, vstride;
+ register int i;
+
+ /* Load a JPEG 2000 "code stream" image file into a pixel buffer for XV.
+ Unlike classical JPEG files, they have no clue about the image's color
+ space, so we check for 8-bit data samples but make no effort to check or
+ convert color spaces, and "what you see is what you get". For now, ignore
+ the "quick" option to return a reduced-resolution or -size image. Return 1
+ on success, or 0 on failure.
+ */
+ if (!(fp = xv_fopen(fname,fmode))) return 0;
+ fbasename = BaseName(fname); /* Input file's base name, for message(s) */
+ if (!(iobuf = SetBuf(fp)))
+ {
+ (void)fclose(fp);
+ SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind);
+ goto L3;
+ }
+
+ /* Before telling the JasPer Library about this file, get its size for display
+ purposes. Non-UNIX systems don't necessarily simulate "stat(2)", so do it
+ crudely but portably by seeking to the end, then back to the beginning.
+ */
+ fseek(fp,0L,2);
+ filesize = ftell(fp);
+ fseek(fp,0L,0);
+
+ /* "jas_stream_close()" will eventually close the input file, so only do it
+ explicitly if no stream can be created:
+ */
+ if (!(str = jas_stream_freopen(fname,fmode,fp))) /* nice if prototype... */
+ {
+ (void)fclose(fp);
+ goto L3;
+ }
+
+ /* It's not clear to me whether the following represents a JasPer Library "bug"
+ but it sure looks goofy: Unless a stream buffer is marked "read only",
+ which only happens when the stream's "fillbuf" method is called, even though
+ our buffers are always "read only", the library will try to flush out buffer
+ contents when the stream is destroyed, which makes it die a horrible death.
+ So, mark the stream buffer proactively:
+ */
+ str->bufmode_ |= JAS_STREAM_RDBUF; /* We will only read the stream buffer */
+ if (!(img = jpc_decode(str,0))) goto L2;
+ if ((vstride = jas_image_numcmpts(img))) /* num. color planes */
+ {
+
+ /* After the image-component streams created, they are left in a "write"
+ state with the streams' cursors positioned at their ends, so "seek" in
+ order to "read" each stream from its beginning.
+ */
+ i = vstride;
+ while (--i >= 0)
+ if (jas_stream_seek(img->cmpts_[i]->stream_,0L,0))
+ {
+ SetISTR(ISTR_WARNING,read_err,fbasename,jpc_kind);
+ goto L1;
+ }
+ }
+ w = jas_image_width(img);
+ h = jas_image_height(img);
+
+ /* avoid buffer overflow */
+ npixels = w * h;
+ bufsize = vstride * npixels;
+ if (w <= 0 || h <= 0 || npixels/w != h || bufsize/vstride != npixels)
+ {
+ (void)fclose(fp);
+ SetISTR(ISTR_WARNING,bad_dims,fbasename);
+ goto L1;
+ }
+ pinfo->normw = pinfo->w = w;
+ pinfo->normh = pinfo->h = h;
+
+ /* Sanity-check the image's color space and no. of colors. For now, accept
+ only "generic" color spaces, not files needing image-specific color
+ correction, but fix that someday...
+ */
+ switch (vstride)
+ {
+ default:
+ SetISTR(ISTR_WARNING,bad_samp,fbasename,vstride,jpc_kind);
+ goto L1;
+ case 1:
+ if ((i = jas_image_cmptprec(img,0)) != 8) /* not 8-bit pixels */
+ {
+ SetISTR(ISTR_WARNING,pixel_size,fbasename,i);
+ goto L1;
+ }
+ s = "Greyscale";
+ pinfo->type = PIC8;
+ pinfo->colType = F_GREYSCALE;
+ i = 256; /* Return fake indexed-color "map" */
+ while (--i >= 0) pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
+ break;
+ case 3:
+
+ /* BEWARE OF KLUDGE: If the image's color space is RGB, assume that the
+ data-sample precision for all color planes is the
+ same. If the color space is YCbCr, assume the luminance (Y = 0th)
+ component has the greatest precision, although the chrominance
+ (Cr = 1st, Cb = 2nd) components are usually sub-sampled.
+ */
+ if ((i = jas_image_cmptprec(img,0)) != 8) /* not 24-bit pixels */
+ {
+ SetISTR(ISTR_WARNING,pixel_size,fbasename,i*3);
+ goto L1;
+ }
+ s = "Color";
+ pinfo->type = PIC24;
+ pinfo->colType = F_FULLCOLOR;
+
+ /* XXX Unlike the IJG JPEG Library, the JasPer Library is apparently
+ unable to quantize colors or tell us whether the image's colors
+ were quantized by its creator, so it seems that we can't return a
+ color map for XV to potentially use 8-bit indexed color. If there
+ *is* an easy way to do it that escapes me, put the code here someday.
+ */
+ }
+ if (!(pinfo->pic = (byte *)malloc(bufsize))) /* image buffer for XV */
+ {
+ SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind);
+ goto L1;
+ }
+ pinfo->frmType = F_JPC;
+ sprintf(pinfo->fullInfo,full_msg,s,jpc_kind,filesize);
+ sprintf(pinfo->shrtInfo,shrt_msg,pinfo->w,pinfo->h,s,jpc_kind);
+ SetISTR(ISTR_INFO,load_msg,pinfo->normw,pinfo->normh,s,jpc_kind,filesize);
+ if (vstride == 1) /* gray-scale image */
+ { register jas_stream_t *c = img->cmpts_[0]->stream_;
+ register byte *p = pinfo->pic;
+
+ /* Since this is a 1-plane image, avoid a lot of errant nonsense in the
+ JasPer Library by sequentially reading all of the data into our buffer
+ directly.
+ */
+ do if ((i = (*c->ops_->read_)(c->obj_,(char *)p,bufsize)) <= 0)
+ {
+ SetISTR(ISTR_WARNING,i < 0 ? read_err : truncated,fbasename,
+ jpc_kind);
+ goto L1;
+ }
+ while ((p += i),(bufsize -= i) > 0);
+ }
+ else /* RGB color image */
+ {
+
+ /* Reading color images is inefficient because JPEG 2000 wants to partition
+ file data into separate image planes (colors), while XV wants data
+ samples from each plane to be interleaved as 3-byte pixels. Apparently
+ the fastest method consists of 3 passes through the XV image buffer,
+ into which we insert the bytes of each component.
+ */
+ i = 0;
+ do /* each color component */
+ { long npix = npixels;
+ register jas_stream_t *c = img->cmpts_[i]->stream_;
+ register byte *p = pinfo->pic + i;
+
+ do /* each pixel */
+ { register int b;
+
+ if ((b = jas_stream_getc(c)) < 0)
+ {
+ SetISTR(ISTR_WARNING,
+ (c->flags_ & JAS_STREAM_EOF) ? truncated : read_err,
+ fbasename,jpc_kind);
+ goto L1;
+ }
+ *p = b;
+ }
+ while ((p += 3),--npix > 0);
+ }
+ while (++i <= 2);
+ }
+ ok = 1; /* Success! */
+L1: jas_image_destroy(img);
+L2: (void)jas_stream_close(str);
+ free(iobuf);
+L3: return ok;
+}
+
+int LoadJP2(char *fname,register PICINFO *pinfo,int quick)
+{
+ jas_image_t *img;
+ jas_stream_t *str;
+ FILE *fp;
+ char *iobuf;
+ const char *s;
+ unsigned long filesize;
+ long w, h, npixels, bufsize;
+ int ok = 0, vstride;
+ register int i;
+
+ /* Load a JPEG 2000 JP2 image file into a pixel buffer for XV, doing any
+ necessary color-space conversion to end up with 8-bit gray scale or 24-bit
+ RGB. For now, ignore the "quick" option to return a reduced-resolution
+ or -size image. Return 1 on success, or 0 on failure.
+ */
+ if (!(fp = xv_fopen(fname,fmode))) return 0;
+ fbasename = BaseName(fname); /* Input file's base name, for message(s) */
+ if (!(iobuf = SetBuf(fp)))
+ {
+ (void)fclose(fp);
+ SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind);
+ goto L3;
+ }
+
+ /* Before telling the JasPer Library about this file, get its size for display
+ purposes. Non-UNIX systems don't necessarily simulate "stat(2)", so do it
+ crudely but portably by seeking to the end, then back to the beginning.
+ */
+ fseek(fp,0L,2);
+ filesize = ftell(fp);
+ fseek(fp,0L,0);
+
+ /* "jas_stream_close()" will eventually close the input file, so only do it
+ explicitly if no stream can be created:
+ */
+ if (!(str = jas_stream_freopen(fname,fmode,fp)))
+ {
+ (void)fclose(fp);
+ goto L3;
+ }
+
+ /* It's not clear to me whether the following represents a JasPer Library "bug"
+ but it sure looks goofy: Unless a stream buffer is marked "read only",
+ which only happens when the stream's "fillbuf" method is called, even though
+ our buffers are always "read only", the library will try to flush out buffer
+ contents when the stream is destroyed, which makes it die a horrible death.
+ So, mark the stream buffer proactively:
+ */
+ str->bufmode_ |= JAS_STREAM_RDBUF; /* We will only read the stream buffer */
+ if (!(img = jp2_decode(str,0))) goto L2;
+ if ((vstride = jas_image_numcmpts(img))) /* num. color planes */
+ {
+
+ /* After the image-component streams created, they are left in a "write"
+ state with the streams' cursors positioned at their ends, so "seek" in
+ order to "read" each stream from its beginning.
+ */
+ i = vstride;
+ while (--i >= 0)
+ if (jas_stream_seek(img->cmpts_[i]->stream_,0L,0))
+ {
+ SetISTR(ISTR_WARNING,read_err,fbasename,jp2_kind);
+ goto L1;
+ }
+ }
+ w = jas_image_width(img);
+ h = jas_image_height(img);
+
+ /* avoid buffer overflow */
+ npixels = w * h;
+ bufsize = vstride * npixels;
+ if (w <= 0 || h <= 0 || npixels/w != h || bufsize/vstride != npixels)
+ {
+ (void)fclose(fp);
+ SetISTR(ISTR_WARNING,bad_dims,fbasename);
+ goto L1;
+ }
+ pinfo->normw = pinfo->w = w;
+ pinfo->normh = pinfo->h = h;
+
+ /* Sanity-check the image's color space and no. of colors. For now, accept
+ only "generic" color spaces, not files needing image-specific color
+ correction, but fix that someday...
+ */
+ switch (vstride)
+ { static char color_space[]={"%s: invalid color space!"};
+
+ default:
+ SetISTR(ISTR_WARNING,bad_samp,fbasename,vstride,jp2_kind);
+ goto L1;
+ case 1:
+ if ( !jas_clrspc_isunknown(i = jas_image_clrspc(img))
+ && jas_clrspc_fam(i) != JAS_CLRSPC_FAM_GRAY
+ )
+ {
+ SetISTR(ISTR_WARNING,color_space,fbasename);
+ goto L1;
+ }
+ if ((i = jas_image_cmptprec(img,0)) != 8) /* not 8-bit pixels */
+ {
+ SetISTR(ISTR_WARNING,pixel_size,fbasename,i);
+ goto L1;
+ }
+ s = "Greyscale";
+ pinfo->type = PIC8;
+ pinfo->colType = F_GREYSCALE;
+ i = 256; /* Return fake indexed-color "map" */
+ while (--i >= 0) pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
+ break;
+ case 3:
+ if (jas_clrspc_isunknown(i = jas_image_clrspc(img)))
+ {
+ SetISTR(ISTR_WARNING,color_space,fbasename);
+ goto L1;
+ }
+ if (jas_clrspc_fam(i) != JAS_CLRSPC_FAM_RGB)
+ { jas_image_t *oimg;
+ jas_cmprof_t *profile;
+
+ /* Here's where the JasPer Library really shines. The only color
+ space that XV handles is RGB, so if that's not what our image
+ uses, then to quote Capt. Kirk: "Make it so!"
+ */
+ if (!(profile = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB)))
+ {
+ SetISTR(ISTR_WARNING,"%s: can't create RGB profile",
+ fbasename);
+ goto L1;
+ }
+ img = jas_image_chclrspc( oimg = img
+ , profile
+ , JAS_CMXFORM_INTENT_PER
+ );
+ jas_cmprof_destroy(profile);
+ if (!img) /* Oops! We failed, so restore original image */
+ {
+ img = oimg;
+ SetISTR(ISTR_WARNING,"%s: can't convert to RGB",fbasename);
+ goto L1;
+ }
+ jas_image_destroy(oimg);
+ }
+
+ /* BEWARE OF KLUDGE: If the image's color space is RGB, assume that the
+ data-sample precision for all color planes is the
+ same. If the color space is YCbCr, assume the luminance (Y = 0th)
+ component has the greatest precision, although the chrominance
+ (Cr = 1st, Cb = 2nd) components are usually sub-sampled.
+ */
+ if ((i = jas_image_cmptprec(img,0)) != 8) /* not 24-bit pixels */
+ {
+ SetISTR(ISTR_WARNING,pixel_size,fbasename,i*3);
+ goto L1;
+ }
+ s = "Color";
+ pinfo->type = PIC24;
+ pinfo->colType = F_FULLCOLOR;
+
+ /* XXX Unlike the IJG JPEG Library, the JasPer Library is apparently
+ unable to quantize colors or tell us whether the image's colors
+ were quantized by its creator, so it seems that we can't return a
+ color map for XV to potentially use 8-bit indexed color. If there
+ *is* an easy way to do it that escapes me, put the code here someday.
+ */
+ }
+ if (!(pinfo->pic = (byte *)malloc(bufsize))) /* image buffer for XV */
+ {
+ SetISTR(ISTR_WARNING,no_mem,fbasename,jp2_kind);
+ goto L1;
+ }
+ pinfo->frmType = F_JP2;
+ sprintf(pinfo->fullInfo,full_msg,s,jp2_kind,filesize);
+ sprintf(pinfo->shrtInfo,shrt_msg,pinfo->w,pinfo->h,s,jp2_kind);
+ SetISTR(ISTR_INFO,load_msg,pinfo->normw,pinfo->normh,s,jp2_kind,filesize);
+ if (vstride == 1) /* gray-scale image */
+ { register jas_stream_t *c = img->cmpts_[0]->stream_;
+ register byte *p = pinfo->pic;
+
+ /* Since this is a 1-plane image, avoid a lot of errant nonsense in the
+ JasPer Library by sequentially reading all of the data into our buffer
+ directly.
+ */
+ do if ((i = (*c->ops_->read_)(c->obj_,(char *)p,bufsize)) <= 0)
+ {
+ SetISTR(ISTR_WARNING,i < 0 ? read_err : truncated,fbasename,
+ jp2_kind);
+ goto L1;
+ }
+ while ((p += i),(bufsize -= i) > 0);
+ }
+ else /* RGB color image */
+ {
+
+ /* Reading color images is inefficient because JPEG 2000 wants to partition
+ file data into separate image planes (colors), while XV wants data
+ samples from each plane to be interleaved as 3-byte pixels. Apparently
+ the fastest method consists of 3 passes through the XV image buffer,
+ into which we insert the bytes of each component.
+ */
+ i = 0;
+ do /* each color component */
+ { long npix = npixels;
+ register jas_stream_t *c = img->cmpts_[i]->stream_;
+ register byte *p = pinfo->pic + i;
+
+ do /* each pixel */
+ { register int b;
+
+ if ((b = jas_stream_getc(c)) < 0)
+ {
+ SetISTR(ISTR_WARNING,
+ (c->flags_ & JAS_STREAM_EOF) ? truncated : read_err,
+ fbasename,jp2_kind);
+ goto L1;
+ }
+ *p = b;
+ }
+ while ((p += 3),--npix > 0);
+ }
+ while (++i <= 2);
+ }
+ ok = 1; /* Success! */
+L1: jas_image_destroy(img);
+L2: (void)jas_stream_close(str);
+ free(iobuf);
+L3: return ok;
+}
+
+/* The following variables and subroutines are used when writing a JPEG 2000
+ file, which is done mainly using call-backs from "X Windows" widgets. The
+ most complicated part of this interface is: managing interactions with a
+ window to request the boat-loads of options that the JasPer Library supports.
+ Start by defining subwindow sizes, plus indices into several arrays of
+ corresponding widget-state variables.
+
+ IMPLEMENTATION NOTES: The following dimensions create a tall, thin window
+ which appears to have considerable empty space at the
+ bottom. Before you complain, click the Precinct Height menu button in order
+ to the tall pop-up subwindow that it generates. If the parent window is made
+ shorter, then this pop-up will be clipped, which is an ugly nuisance. I
+ don't know how to make the pop-up visible outside its parent's borders; do
+ you? If there's some way to make "X Windows" do this, then we might consider
+ making the parent shorter.
+
+ Note that there is currently no mechanism to program the no. of intermediate
+ layers used by the encoder, or their rates. This is potentially a large and
+ complicated data-entry problem, and perhaps someday we can invent a clever
+ solution using the rest of the parent window's space.
+*/
+# define JP2KW 275 /* Window width, in pixels */
+# define JP2KH 400 /* Window height, in pixels */
+# define BUTTW 51 /* Button width, in pixels (odd for half-toning) */
+# define BUTTH 20 /* Button height, in pixels */
+# define MENUW 75 /* Menu-button width, in pixels (odd for half-toning) */
+# define MENUH 24 /* Menu-button height, in pixels */
+# define RBUTH 20 /* Radio button height, in pixels */
+# define RBUTW 51 /* Radio button width, in pixels (odd for half-toning) */
+# define TEXTH (LINEHIGH+5) /* Text subwindow height, in pixels */
+# define TEXTW 75 /* Text subwindow width, in pixels */
+
+# define J_BOK 0 /* Boolean "Ok" button */
+# define J_BCANC 1 /* Boolean "Cancel" button */
+# define J_NBUTT 2 /* No. of regular button widgets */
+
+# define J_CSOP 0 /* Boolean encoding-style option buttons */
+# define J_CEPH 1
+# define J_CLAZY 2
+# define J_CTERM 3
+# define J_CSEGS 4
+# define J_CVCAU 5
+# define J_CPTRM 6
+# define J_CRSTP 7
+# define J_NCHKB 8 /* No. of check-box button widgets */
+
+# define J_MCBXW 0 /* 1-of-N menu-selection buttons */
+# define J_MCBXH 1
+# define J_MPREW 2
+# define J_MPREH 3
+# define J_MPROG 4
+# define J_NMENU 5 /* No. of menu-button widgets */
+
+# define J_TGBIT 0 /* (Unsigned numeric) string subwindows */
+# define J_TRES 1
+# define J_TRATE 2
+# define J_NTEXT 3 /* No. of text subwindows */
+
+static BUTT button[J_NBUTT];
+static CBUTT chkbut[J_NCHKB];
+static MBUTT menu[J_NMENU];
+static RBUTT *radio;
+static Window text[J_NTEXT];
+static int colorType, format, textval[J_NTEXT];
+static const char *ProgList[]={"lrcp","rlcp","rpcl","pcrl","cprl"};
+
+void CreateJP2KW(void)
+{
+ static const char EXP2_0[] ={ "1"}, /* Successive powers of 2 */
+ EXP2_1[] ={ "2"},
+ EXP2_2[] ={ "4"},
+ EXP2_3[] ={ "8"},
+ EXP2_4[] ={ "16"},
+ EXP2_5[] ={ "32"},
+ EXP2_6[] ={ "64"},
+ EXP2_7[] ={ "128"},
+ EXP2_8[] ={ "256"},
+ EXP2_9[] ={ "512"},
+ EXP2_10[]={ "1024"},
+ EXP2_11[]={ "2048"},
+ EXP2_12[]={ "4096"},
+ EXP2_13[]={ "8192"},
+ EXP2_14[]={"16384"},
+ EXP2_15[]={"32768"};
+ static const char *CBoxList[]=
+ {
+ EXP2_1 ,EXP2_2 ,EXP2_3 ,EXP2_4 ,EXP2_5,EXP2_6 ,EXP2_7 ,EXP2_8 ,EXP2_9,
+ EXP2_10,EXP2_11
+ };
+ static const char *PrecList[]=
+ {
+ EXP2_0,EXP2_1,EXP2_2 ,EXP2_3 ,EXP2_4 ,EXP2_5 ,EXP2_6 ,EXP2_7 ,
+ EXP2_8,EXP2_9,EXP2_10,EXP2_11,EXP2_12,EXP2_13,EXP2_14,EXP2_15
+ };
+ static const char hstr[]={"Height"}, wstr[]={"Width"};
+
+ if (!(jp2kW = CreateWindow( "xvjp2k"
+ , "XVjp2k"
+ , 0
+ , JP2KW
+ , JP2KH
+ , infofg
+ , infobg
+ , 0
+ )
+ )
+ ) FatalError("can't create JPEG 2000 window!");
+ XSelectInput(theDisp,jp2kW,ExposureMask|ButtonPressMask|KeyPressMask);
+
+ /* Create a row of 2 boolean-valued, regular buttons ("Ok" and "Cancel") in the
+ window's bottom right corner.
+ */
+ BTCreate(&button[J_BOK ],jp2kW,
+ JP2KW-2*BUTTW-20,JP2KH-10-BUTTH-1,BUTTW,BUTTH,
+ "Ok" ,infofg,infobg,hicol,locol);
+ BTCreate(&button[J_BCANC],jp2kW,
+ JP2KW- BUTTW-10,JP2KH-10-BUTTH-1,BUTTW,BUTTH,
+ "Cancel",infofg,infobg,hicol,locol);
+
+ /* Create a vertical column of 8 boolean-valued, check-box buttons (for
+ encoding-style options) down the window's left side.
+ */
+ CBCreate(&chkbut[J_CSOP] ,jp2kW,
+ 10,10+ASCENT+SPACING+2*LINEHIGH+0*BUTTH,
+ "sop" ,infofg,infobg,hicol,locol);
+ CBCreate(&chkbut[J_CEPH] ,jp2kW,
+ 10,10+ASCENT+SPACING+2*LINEHIGH+1*BUTTH,
+ "eph" ,infofg,infobg,hicol,locol);
+ CBCreate(&chkbut[J_CLAZY],jp2kW,
+ 10,10+ASCENT+SPACING+2*LINEHIGH+2*BUTTH,
+ "lazy" ,infofg,infobg,hicol,locol);
+ CBCreate(&chkbut[J_CTERM],jp2kW,
+ 10,10+ASCENT+SPACING+2*LINEHIGH+3*BUTTH,
+ "termall" ,infofg,infobg,hicol,locol);
+ CBCreate(&chkbut[J_CSEGS],jp2kW,
+ 10,10+ASCENT+SPACING+2*LINEHIGH+4*BUTTH,
+ "segsym" ,infofg,infobg,hicol,locol);
+ CBCreate(&chkbut[J_CVCAU],jp2kW,
+ 10,10+ASCENT+SPACING+2*LINEHIGH+5*BUTTH,
+ "vcausal" ,infofg,infobg,hicol,locol);
+ CBCreate(&chkbut[J_CPTRM],jp2kW,
+ 10,10+ASCENT+SPACING+2*LINEHIGH+6*BUTTH,
+ "pterm" ,infofg,infobg,hicol,locol);
+ CBCreate(&chkbut[J_CRSTP],jp2kW,
+ 10,10+ASCENT+SPACING+2*LINEHIGH+7*BUTTH,
+ "resetprob",infofg,infobg,hicol,locol);
+ /* Create text subwindows for unsigned decimal integer values. */
+
+ text[J_TGBIT] = XCreateSimpleWindow(theDisp,jp2kW,
+ JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+0*TEXTH,TEXTW,TEXTH,
+ 1,infofg,infobg);
+ XSelectInput(theDisp,text[J_TGBIT],ExposureMask|KeyPressMask);
+ text[J_TRES ] = XCreateSimpleWindow(theDisp,jp2kW,
+ JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+1*TEXTH,TEXTW,TEXTH,
+ 1,infofg,infobg);
+ XSelectInput(theDisp,text[J_TRES ],ExposureMask|KeyPressMask);
+ text[J_TRATE] = XCreateSimpleWindow(theDisp,jp2kW,
+ JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+2*TEXTH,TEXTW,TEXTH,
+ 1,infofg,infobg);
+ XSelectInput(theDisp,text[J_TRATE],ExposureMask|KeyPressMask);
+
+ /* Create a row of 2 boolean-valued radio buttons (for the "Rate" subwindow
+ value's unit of measure). The 1st button is "selected" by default.
+ */
+ radio = RBCreate(0,jp2kW,
+ JP2KW-19*RBUTW/8-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+3*TEXTH+4,
+ "Percent",infofg,infobg,hicol,locol);
+ (void)RBCreate(radio,jp2kW,
+ JP2KW-1*RBUTW-10 ,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+3*TEXTH+4,
+ "Bytes",infofg,infobg,hicol,locol);
+
+ /* Create pop-up menu-selection buttons after mapping the above subwindows,
+ since we don't want the pop-up menus mapped unless the corresponding button
+ is selected.
+ */
+ XMapSubwindows(theDisp,jp2kW);
+ MBCreate(&menu[J_MCBXW],jp2kW,
+ JP2KW-2*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+0*MENUH,MENUW,MENUH,
+ wstr ,CBoxList,sizeof CBoxList/sizeof *CBoxList,infofg,infobg,
+ hicol,locol);
+ MBCreate(&menu[J_MCBXH],jp2kW,
+ JP2KW-2*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+1*MENUH,MENUW,MENUH,
+ hstr ,CBoxList,sizeof CBoxList/sizeof *CBoxList,infofg,infobg,
+ hicol,locol);
+ MBCreate(&menu[J_MPREW],jp2kW,
+ JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+0*MENUH,MENUW,MENUH,
+ wstr ,PrecList,sizeof PrecList/sizeof *PrecList,infofg,infobg,
+ hicol,locol);
+ MBCreate(&menu[J_MPREH],jp2kW,
+ JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+1*MENUH,MENUW,MENUH,
+ hstr ,PrecList,sizeof PrecList/sizeof *PrecList,infofg,infobg,
+ hicol,locol);
+ MBCreate(&menu[J_MPROG],jp2kW,
+ JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+2*MENUH,MENUW,MENUH,
+ "Order",ProgList,sizeof ProgList/sizeof *ProgList,infofg,infobg,
+ hicol,locol);
+
+ /* Initialize values represented by widgets, which should correspond to default
+ compiled into the JasPer Library. Unfortunately, as of Version 1.701 there
+ is no easy way for an application to extract these from the library, so the
+ following code might get out of sync over time:
+ */
+ menu[J_MCBXW].hascheck = 1; menu[J_MCBXW].flags[ 5] = 1;
+ menu[J_MCBXH].hascheck = 1; menu[J_MCBXH].flags[ 5] = 1;
+ menu[J_MPREW].hascheck = 1; menu[J_MPREW].flags[15] = 1;
+ menu[J_MPREH].hascheck = 1; menu[J_MPREH].flags[15] = 1;
+ menu[J_MPROG].hascheck = 1; menu[J_MPROG].flags[ 0] = 1;
+ textval[J_TGBIT] = 2; /* No. of guard bits */
+ textval[J_TRES ] = 6; /* Max. no. of resolution levels */
+ textval[J_TRATE] = 100; /* Rate = 100% */
+}
+
+void JP2KSaveParams(int fmt,char *fname,int col) /* Save output-file parms */
+{
+ format = fmt; /* Desired file format: F_JPC|F_JP2 */
+ fbasename = fname; /* ->Output file path */
+ colorType = col; /* Desired color space: F_GREYSCALE|... */
+}
+
+static void StoreJP2K(char *options)
+{
+ static jas_image_cmptparm_t parm[3]= /* Image parameters */
+ {{0,0,1,1,0,0,8,0},{0,0,1,1,0,0,8,0},{0,0,1,1,0,0,8,0}};
+ static char nomem[]={"StoreJP2K: out of memory\n"},
+ write[]={"w"};
+ jas_image_t *img;
+ jas_stream_t *str;
+ FILE *fp, *fp2;
+ byte *pic, *r, *g, *b;
+ const char *filename;
+ char *iobuf = 0;
+ unsigned long imagesize;
+ jas_clrspc_t color_space;
+ int nc, w, h, pfree, ptype, error = 1;
+ register int i;
+
+ /* This is a generic subroutine for writing JPEG 2000 image files using the
+ JasPer Library. Our argument is an ASCII string, containing a Space (" ")-
+ separated sequence of encoder options that currently aren't well documented.
+ Most of the work is identical for both ".jpc" and ".jp2" files. Start by
+ verifying that the output file can be opened, then get an image buffer from
+ XV and begin crunching it into a suitable form for the JasPer Library.
+ */
+ if (!(fp = OpenOutFile(filename = fbasename))) return; /* Oops! */
+ setbuf(fp,0); /* We don't really use this file pointer for I/O; see below */
+ fbasename = BaseName(filename);
+ WaitCursor();
+ pic = GenSavePic(&ptype,&w,&h,&pfree,&nc,&r,&g,&b);
+ imagesize = w*h;
+ if (ptype == PIC24) imagesize *= 3;
+
+ /* As an optimization to save file space, even if our user didn't ask to store
+ a gray-scale image, check whether we could and, if so, do it anyway.
+ */
+ if (colorType != F_GREYSCALE) /* can we force a gray-scale image? */
+ {
+ if (ptype == PIC8)
+ {
+ i = nc;
+ while (--i >= 0 && r[i] == g[i] && r[i] == b[i]);
+ }
+ else /* PIC24 */
+ { register byte *p = pic + imagesize;
+
+ while ((p -= 3) >= pic && p[0] == p[1] && p[0] == p[2]);
+ i = p-pic;
+ };
+ if (i < 0) colorType = F_GREYSCALE; /* We made it all the way through */
+ };
+
+ /* If XV is currently color-mapping the image, make a color-mapped copy so that
+ the map needn't be transmitted in the output file.
+ */
+ if ((i = (colorType != F_GREYSCALE) << 1 | (ptype != PIC8)) != 3)
+ { byte *tmp = pic, *last = pic + imagesize;
+ register byte *from = tmp, *to = pic;
+
+ if (!(pic = (byte *)malloc(imagesize))) FatalError(nomem);
+ switch (i)
+ {
+
+ /* Color-map 8->8 bit image. */
+
+ case 0: do
+ {
+ i = *from;
+ *to++ = MONO(r[i],g[i],b[i]);
+ }
+ while (++from < last);
+ break;
+
+ /* Color-map 24->8 bit image. */
+
+ case 1: do *to++ = MONO(from[0],from[1],from[2]);
+ while ((from += 3) < last);
+ break;
+
+ /* Color-map 8->24 bit image. */
+
+ case 2: do
+ {
+ i = *from;
+ *to++ = r[i]; *to++ = g[i]; *to++ = b[i];
+ }
+ while (++from < last);
+ break;
+ };
+ if (pfree) free(tmp); /* Release the original image buffer if we can */
+ pfree = 1; /* Let the modified buffer be released later */
+ };
+
+ /* Initialize various image-file parameter variables. */
+
+ parm[0].width = w;
+ parm[0].height = h;
+ if (colorType == F_GREYSCALE) /* gray-scale image */
+ {
+ ptype = 1; /* No. of color planes */
+ color_space = JAS_CLRSPC_SGRAY;
+ }
+ else /* RGB color image */
+ {
+ ptype = 3; /* No. of color planes */
+ color_space = JAS_CLRSPC_SRGB;
+ parm[2].width = parm[1].width = parm[0].width;
+ parm[2].height = parm[1].height = parm[0].height;
+ };
+
+ /* Now comes a egregious hack: The JasPer Library will eventually want to
+ close the output file that it writes, but since XV opened the file, XV also
+ thinks it has the right to close the file! In order to pacify them both,
+ we duplicate the file pointer and let the JasPer Library have it, while we
+ retain the original for XV.
+
+ XXX This code is very UNIX-specific; what's an equivalent hack for Windows?
+ */
+ if (!(fp2 = (i = dup(fileno(fp))) >= 0 ? fdopen(i,write) : 0))
+ FatalError("StoreJP2K: can't duplicate output file pointer\n");
+ if (!(iobuf = SetBuf(fp2)))
+ {
+ (void)fclose(fp2);
+ FatalError(nomem);
+ };
+
+ /* Hand our output file to the JasPer Library and create an image object.
+ "jas_stream_close()" will eventually close our output file, so only do it
+ explicitly if no stream can be created. If everything looks copacetic,
+ then write our buffer contents to the image components' streams.
+ */
+ if (!(str = jas_stream_freopen(filename,write,fp2)))
+ {
+ (void)fclose(fp2);
+ FatalError("StoreJP2K: can't open output stream\n");
+ };
+ if (!(img = jas_image_create(ptype,parm,color_space))) goto L2;
+ if (ptype == 1)
+ { register jas_stream_t *c = img->cmpts_[0]->stream_;
+ register byte *p = pic;
+
+ /* Since this is a 1-plane image, avoid a lot of errant nonsense in the
+ JasPer Library by sequentially writing all of the data directly from our
+ buffer.
+ */
+ jas_image_setcmpttype(img,0,JAS_IMAGE_CT_GRAY_Y);
+ img->cmpts_[0]->type_ = JAS_IMAGE_CT_GRAY_Y;
+ do if ((i = (*c->ops_->write_)(c->obj_,(char *)p,imagesize)) <= 0)
+ goto L1;
+ while ((p += i),(imagesize -= i) > 0);
+ if (jas_stream_flush(c) < 0) goto L1;
+ }
+ else /* RGB color image */
+ {
+
+ /* Writing color images is inefficient because JPEG 2000 wants to partition
+ file data into separate image planes (colors), while XV wants data
+ samples from each plane to be interleaved as 3-byte pixels. Apparently
+ the fastest method consists of 3 passes through the XV image buffer,
+ from which we extract the bytes of each component.
+ */
+ i = 0;
+ do /* each color component */
+ { long npix = imagesize/3;
+ register jas_stream_t *c = img->cmpts_[i]->stream_;
+ register byte *p = pic + i;
+
+ jas_image_setcmpttype(img,i,i+JAS_IMAGE_CT_RGB_R);
+ do if (jas_stream_putc(c,*p) < 0) goto L1;
+ while ((p += 3),--npix > 0);
+ if (jas_stream_flush(c) < 0) goto L1;
+ }
+ while (++i <= 2);
+ };
+ if ( (*(format == F_JPC ? jpc_encode : jp2_encode))(img,str,options) >= 0
+ && jas_stream_flush(str) >= 0
+ ) error = 0; /* Success! */
+L1: jas_image_destroy(img);
+L2: (void)jas_stream_close(str);
+ if (iobuf) free(iobuf);
+ if (pfree) free(pic);
+ if (!CloseOutFile(fp,filename,error)) DirBox(0);
+ SetCursors(-1);
+}
+
+void JP2KDialog(int vis)
+{
+ if ((jp2kUp = vis)) CenterMapWindow(jp2kW,0,0,JP2KW,JP2KH);
+ else XUnmapWindow(theDisp,jp2kW);
+}
+
+static void TWRedraw(Window w,unsigned int val)
+{
+ char buf[11];
+ register int i;
+
+ /* Draw a 1-line numeric text string in the specified window, representing the
+ argument value as a left-justified unsigned decimal integer, followed by a
+ "cursor" icon.
+ */
+ sprintf(buf,"%u",val);
+ if (ctrlColor) XClearArea(theDisp,w,2,2,TEXTW-4,TEXTH-4,False);
+ else XClearWindow(theDisp,w);
+ Draw3dRect(w,0,0,TEXTW-1,TEXTH-1,R3D_IN,2,hicol,locol,infobg);
+ XSetForeground(theDisp,theGC,infofg);
+ XDrawString(theDisp,w,theGC,3,ASCENT+3,buf,i = strlen(buf));
+
+ /* Draw a "cursor" icon after the numeric string. */
+
+ i = XTextWidth(mfinfo,buf,i);
+ XDrawLine(theDisp,w,theGC,i+3,2 ,i+3,2+CHIGH+1);
+ XDrawLine(theDisp,w,theGC,i+3,2+CHIGH+1,i+5,2+CHIGH+3);
+ XDrawLine(theDisp,w,theGC,i+3,2+CHIGH+1,i+1,2+CHIGH+3);
+}
+
+int JP2KCheckEvent(register XEvent *xev)
+{
+ int ok = 0;
+
+ /* Check whether the argument "X Windows" event is for one of our subwindows.
+ If it is, handle the event and return 1; otherwise, return 0.
+ */
+ if (!jp2kUp) return 0;
+ switch (xev->type)
+ { KeySym ks;
+ int len;
+ char buf[128];
+ register int i;
+
+ /* Throw away excess "expose" events for "dumb" windows. */
+
+ case Expose :
+# define E ((XExposeEvent *)xev)
+ if (E->window == jp2kW)
+ { XRectangle rect;
+
+ rect.x = E->x ; rect.y = E->y ;
+ rect.width = E->width; rect.height = E->height;
+ XSetClipRectangles(theDisp,theGC,0,0,&rect,1,Unsorted);
+ XSetForeground(theDisp,theGC,infofg);
+ XSetBackground(theDisp,theGC,infobg);
+ i = sizeof button/sizeof *button;
+ while (--i >= 0) BTRedraw(&button[i]);
+ i = sizeof chkbut/sizeof *chkbut;
+ while (--i >= 0) CBRedraw(&chkbut[i]);
+ i = sizeof menu/sizeof *menu;
+ while (--i >= 0) MBRedraw(&menu[i]);
+ RBRedraw(radio,-1);
+ DrawString(jp2kW,10,10+ASCENT,"Save JPEG 2000 File...");
+ DrawString(jp2kW,10,10+ASCENT+2*LINEHIGH,"Style options:");
+ DrawString(jp2kW,JP2KW-2*MENUW-10,10+ASCENT+2*LINEHIGH,
+ "Coding Blk");
+ DrawString(jp2kW,JP2KW-1*MENUW-10,10+ASCENT+2*LINEHIGH,
+ " Precinct");
+ DrawString(jp2kW,
+ JP2KW-2*MENUW-10,10+ASCENT+SPACING+3*LINEHIGH+2*MENUH,
+ "Progression:");
+ DrawString(jp2kW,
+ JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+0*TEXTH,
+ "Guard bits:");
+ DrawString(jp2kW,
+ JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+1*TEXTH,
+ "Res levels:");
+ DrawString(jp2kW,
+ JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+2*TEXTH,
+ "Rate:");
+ XSetClipMask(theDisp,theGC,None);
+ ok = 1;
+ break;
+ };
+ i = sizeof text/sizeof *text;
+ while (--i >= 0 && E->window != text[i]);
+ if (i >= 0)
+ {
+ TWRedraw(E->window,textval[i]);
+ ok = 1;
+ };
+ break;
+# undef E
+
+ /* Check whether the user pressed one of our buttons. */
+
+ case ButtonPress:
+# define E ((XButtonEvent *)xev)
+ if (E->button == Button1 && E->window == jp2kW)
+ { register int j;
+
+ ok = 1; /* Check whether a regular button was pressed */
+ i = sizeof button/sizeof *button;
+ while ( --i >= 0
+ && !PTINRECT(E->x,E->y,button[i].x,button[i].y,button[i].w,button[i].h)
+ );
+ if (i >= 0) /* our button was pressed */
+ { char options[1024];
+ register char *p;
+ register const char *q;
+
+ if (!BTTrack(&button[i])) break; /* Ignore it */
+ if (i != J_BOK) /* must be "Cancel" button */
+ {
+ JP2KDialog(0);
+ break;
+ };
+
+ /* Our user hit the "Ok" button. At this point, we have an ugly
+ job to do: JasPer Library encoder options must be specified
+ as an ASCII string of Space (" ")-separated <tag>[=<value>]
+ entries, so we must collect the values of all of our widgets
+ and subwindows, determine whether our user has requested any
+ non-default values, then build the string only for the JasPer
+ Library to immediately tear it apart again. Yechh!
+ */
+ if ((unsigned)textval[J_TGBIT]-1 > 7)
+ {
+ OpenAlert("No. of guard bits must be 1-8");
+ sleep(3);
+ CloseAlert();
+ break;
+ };
+ if ((unsigned)textval[J_TRES ] <= 0)
+ {
+ OpenAlert("Maximum resolution levels must be >= 1");
+ sleep(3);
+ CloseAlert();
+ break;
+ };
+
+ /* XXX Should we check and complain if the rate is zero?
+ JasPer Library Version 1.701 apparently accepts that
+ value, even though it seems kinda weird.
+ */
+ p = options;
+ i = 0;
+ do if ((j = MBWhich(&menu[i])) != 5)
+ { static const char *parm[2] =
+ {"cblkwidth=%u", "cblkheight=%u"};
+
+ if (p > options) *p++ = ' ';
+ sprintf(p,parm[i-J_MCBXW],++j);
+ while (*++p);
+ }
+ while (++i <= J_MCBXH);
+ do if ((j = MBWhich(&menu[i])) < 15)
+ { static const char *parm[2] =
+ {"prcwidth=%u", "prcheight=%u"};
+
+ if (p > options) *p++ = ' ';
+ sprintf(p,parm[i-J_MPREW],j);
+ while (*++p);
+ }
+ while (++i <= J_MPREH);
+ if ((j = MBWhich(&menu[i])))
+ {
+ if (p > options) *p++ = ' ';
+ *p++ = 'p'; *p++ = 'r'; *p++ = 'g'; *p = '=';
+ q = ProgList[j];
+ while ((*++p = *q++));
+ };
+ if ((i = textval[J_TRES ]) != 6)
+ {
+ if (p > options) *p++ = ' ';
+ sprintf(p,"numrlvls=%u",i);
+ while (*++p);
+ };
+ i = 0;
+ do if (chkbut[i].val) /* append this encoding option */
+ {
+ if (p > options) *p++ = ' ';
+ q = chkbut[i].str;
+ while ((*p++ = *q++));
+ *--p = '\000';
+ }
+ while (++i < sizeof chkbut/sizeof *chkbut);
+ if ((i = textval[J_TGBIT]) != 2)
+ {
+ if (p > options) *p++ = ' ';
+ sprintf(p,"numgbits=%u",i);
+ while (*++p);
+ };
+ if ((i = textval[J_TRATE]) != 100)
+ {
+ if (p > options) *p++ = ' ';
+ *p++ = 'r'; *p++ = 'a'; *p++ = 't'; *p++ = 'e';
+ *p++ = '=';
+ if (i) /* non-zero rate */
+ {
+ if (RBWhich(radio)) sprintf(p,"%uB",i); /* # Bytes */
+ else /* the value is a percentage */
+ {
+ if (i > 100) i = 200; /* => Raw size + 1 */
+ sprintf(p,"%u.%.2u",i/100,i%100);
+ }
+ while (*++p);
+ }
+ else /* rate = 0 */
+ {
+
+ /* XXX This is apparently valid, since JasPer Library
+ Version 1.701 doesn't complain about it.
+ */
+ *p++ = '0';
+ *p = '\000';
+ }
+ };
+ StoreJP2K(options); /* Finally, do the *real* work! */
+ JP2KDialog(0);
+ p = GetDirFullName();
+ if (!ISPIPE(*p))
+ {
+ XVCreatedFile(p);
+ StickInCtrlList(0);
+ };
+ break;
+ };
+
+ /* See whether a check-box button was pressed. */
+
+ i = sizeof chkbut/sizeof *chkbut;
+ while (--i >= 0 && !CBClick(&chkbut[i],E->x,E->y));
+ if (i >= 0) /* our button was pressed */
+ {
+ (void)CBTrack(&chkbut[i]);
+ break;
+ };
+
+ /* See whether a menu button was pressed. */
+
+ i = sizeof menu/sizeof *menu;
+ while (--i >= 0 && !MBClick(&menu[i],E->x,E->y));
+ if (i >= 0) /* our button was pressed */
+ { register int j;
+
+ if ((j = MBTrack(&menu[i])) >= 0)
+ {
+ switch (i)
+ {
+
+ /* The JasPer Library constrains a coding box's area
+ (width x height) to be <= 4096 pixels, so if this
+ button-press would violate that condition, then
+ quietly limit the box's orthogonal dimension by just
+ enough to compensate.
+ */
+ case J_MCBXH:
+ case J_MCBXW: if (MBWhich(&menu[!i]) + j >= 10)
+ MBSelect(&menu[!i],10 - j);
+ };
+ MBSelect(&menu[i],j);
+ MBSetActive(&menu[i],1);
+ };
+ break;
+ };
+
+ /* See whether a radio button was pressed. */
+
+ if ( (i = RBClick(radio,E->x,E->y)) >= 0 /* button pressed */
+ && RBTrack(radio,i)
+ )
+ {
+ RBSelect(radio,i);
+ RBSetActive(radio,i,1);
+ };
+ break;
+ };
+ XBell(theDisp,50);
+ break;
+# undef E
+
+ /* Translate a few key-press events into simulated button events. */
+
+ case KeyPress :
+# define E ((XKeyEvent *)xev)
+ buf[len = XLookupString(E,buf,sizeof buf,&ks,0)] = '\000';
+ RemapKeyCheck(ks,buf,&len);
+ if (E->window == jp2kW)
+ {
+ ok = 1;
+ if (len > 0)
+ switch (buf[0])
+ {
+ case '\r' :
+ case '\n' : FakeButtonPress(&button[J_BOK ]);
+ break;
+ case '\033': FakeButtonPress(&button[J_BCANC]);
+ };
+ break;
+ };
+ i = sizeof text/sizeof *text;
+ while (--i >= 0 && E->window != text[i]);
+ if (i >= 0) /* a key was pressed in our text window */
+ { int oldval = textval[i]; /* Save this subwindow's old value */
+ register int c, j = 0;
+
+ /* This is a *very* simple text-input editing loop that assembles an
+ an unsigned integer from successive ASCII decimal digits, typed
+ into one of our 1-line subwindows. For convenience, the only
+ character recognized is Backspace.
+ */
+ ok = 1;
+ L: if (j >= len) break;
+ if ((unsigned)(c = buf[j++] - '0') <= 9)
+ {
+ TWRedraw(text[i],textval[i] = textval[i]*10 + c);
+ goto L;
+ };
+ if ((c += '0') == '\b')
+ {
+ TWRedraw(text[i],textval[i] = textval[i]/10);
+ goto L;
+ };
+ textval[i] = oldval;
+ };
+ XBell(theDisp,50);
+# undef E
+ };
+ return ok;
+}
+
+
+/*******************************************/
+void
+VersionInfoJP2K() /* GRR 20070304 */
+{
+ fprintf(stderr, " Compiled with libjasper %s; using libjasper %s.\n",
+ JAS_VERSION, jas_getversion());
+}
+
+#endif /* HAVE_JP2K */
diff -u -r --new-file xv-3.10a.orig/xvmag.c xv-3.10a/xvmag.c
--- xv-3.10a.orig/xvmag.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvmag.c 2005-04-18 00:56:58.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvmaki.c xv-3.10a/xvmaki.c
--- xv-3.10a.orig/xvmaki.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvmaki.c 2005-04-18 00:57:01.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvmgcsfx.c xv-3.10a/xvmgcsfx.c
--- xv-3.10a.orig/xvmgcsfx.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvmgcsfx.c 2007-04-15 17:02:32.000000000 -0500
@@ -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 const 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 const 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 -u -r --new-file xv-3.10a.orig/xvml.c xv-3.10a/xvml.c
--- xv-3.10a.orig/xvml.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvml.c 2005-04-18 00:57:34.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvml.h xv-3.10a/xvml.h
--- xv-3.10a.orig/xvml.h 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvml.h 2005-04-18 00:57:45.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvpcd.c xv-3.10a/xvpcd.c
--- xv-3.10a.orig/xvpcd.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvpcd.c 2007-05-13 20:02:13.000000000 -0500
@@ -0,0 +1,1311 @@
+/*
+ * 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"
+
+#ifdef HAVE_PCD
+
+#include <memory.h>
+#ifndef alloca
+# include <alloca.h> /* "not in POSIX or SUSv3" according to Linux man page */
+#endif /* ...but required for Sun C compiler (alloca = macro) */
+
+#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(const char *, const 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;
+ const 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((char *)&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((char *)(p + (2*h-2)*mw), /* 2nd last row */
+ (char *)(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(const char *fname, const 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(const 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)
+{
+ const 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 -u -r --new-file xv-3.10a.orig/xvpi.c xv-3.10a/xvpi.c
--- xv-3.10a.orig/xvpi.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvpi.c 2005-04-18 00:57:04.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvpic.c xv-3.10a/xvpic.c
--- xv-3.10a.orig/xvpic.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvpic.c 2005-04-18 00:57:08.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvpic2.c xv-3.10a/xvpic2.c
--- xv-3.10a.orig/xvpic2.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvpic2.c 2007-04-15 17:02:32.000000000 -0500
@@ -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 const 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 -u -r --new-file xv-3.10a.orig/xvpng.c xv-3.10a/xvpng.c
--- xv-3.10a.orig/xvpng.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvpng.c 2007-05-13 19:53:28.000000000 -0500
@@ -0,0 +1,1173 @@
+/*
+ * 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).
+ * The copyright will be passed on to JB at some future point if he
+ * so desires.
+ *
+ * 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. See README.jumbo for details.
+ */
+
+#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 const 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;
+
+
+#ifdef PNG_NO_STDIO
+/* NOTE: Some sites configure their version of the PNG Library without
+ * Standard I/O Library interfaces in order to avoid unnecessary inter-
+ * library dependencies at link time for applications that don't need Standard
+ * I/O. If your site is one of these, the following skeletal stubs, copied
+ * from libpng code, should be enough for this module. --Scott B. Marovich,
+ * Hewlett-Packard Laboratories, March 2001.
+ */
+static void
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+ if (fread(data,1,length,(FILE *)png_ptr->io_ptr) != length)
+ png_error(png_ptr, "Read Error");
+}
+
+static void
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ if (fwrite(data, 1, length, (FILE *)png_ptr->io_ptr) != length)
+ png_error(png_ptr, "Write Error");
+}
+#endif /* PNG_NO_STDIO */
+
+
+/**************************************************************************/
+/* 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;
+{
+ const char *title = "Save PNG file...";
+
+ char ctitle1[20];
+ const char *ctitle2 = "Useful range";
+ const char *ctitle3 = "is 2 - 7.";
+ const char *ctitle4 = "Uncompressed = 0";
+
+ const 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;
+ /* FIXME? what's diff between picComments and WriteGIF's comment arg? */
+{
+ png_struct *png_ptr;
+ png_info *info_ptr;
+ png_color palette[256];
+ png_textp text;
+ byte r1[256], g1[256], b1[256]; /* storage for deduped palette */
+ byte pc2nc[256]; /* for duplicated-color remapping (1st level) */
+ byte remap[256]; /* for bw/grayscale remapping (2nd level) */
+ int i, j, numuniqcols=0, 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");
+ 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;
+ }
+
+#ifdef PNG_NO_STDIO
+ png_set_write_fn(png_ptr, fp, png_default_write_data, NULL);
+ png_set_error_fn(png_ptr, NULL, png_xv_error, png_xv_warning);
+#else
+ png_init_io(png_ptr, fp);
+#endif
+
+ 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 */
+
+
+ /* GRR 20070331: remap palette to eliminate duplicated colors (as in
+ * xvgifwr.c) */
+ if (ptype == PIC8) {
+ for (i=0; i<256; ++i) {
+ pc2nc[i] = r1[i] = g1[i] = b1[i] = 0;
+ }
+
+ /* compute number of unique colors */
+ numuniqcols = 0;
+
+ for (i=0; i<numcols; ++i) {
+ /* see if color #i is already used */
+ for (j=0; j<i; ++j) {
+ if (rmap[i] == rmap[j] && gmap[i] == gmap[j] && bmap[i] == bmap[j])
+ break;
+ }
+
+ if (j==i) { /* wasn't found */
+ pc2nc[i] = numuniqcols;
+ r1[numuniqcols] = rmap[i]; /* i.e., r1[pc2nc[i]] == rmap[i] */
+ g1[numuniqcols] = gmap[i];
+ b1[numuniqcols] = bmap[i];
+ ++numuniqcols;
+ }
+ else pc2nc[i] = pc2nc[j];
+ }
+ }
+
+
+ /* Appendix G.2 of user manual claims colorType will never be F_REDUCED... */
+ 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 /* ptype == PIC8 */ {
+ linesize = w;
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+ if (numuniqcols <= 2)
+ info_ptr->bit_depth = 1;
+ else
+ if (numuniqcols <= 4)
+ info_ptr->bit_depth = 2;
+ else
+ if (numuniqcols <= 16)
+ info_ptr->bit_depth = 4;
+ else
+ info_ptr->bit_depth = 8;
+
+ for (i = 0; i < numuniqcols; i++) {
+ palette[i].red = r1[i];
+ palette[i].green = g1[i];
+ palette[i].blue = b1[i];
+ }
+ info_ptr->num_palette = numuniqcols;
+ 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(r1[0], g1[0], b1[0]) > MONO(r1[1], g1[1], b1[1])) {
+ remap[0] = 1;
+ remap[1] = 0;
+ }
+ else {
+ remap[0] = 0;
+ remap[1] = 1;
+ }
+ linesize = w;
+ }
+ else /* F_GREYSCALE */ {
+ 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 /* ptype == PIC8 */ {
+ int low_precision;
+
+ linesize = w;
+
+ /* NOTE: currently remap[] is the _secondary_ remapping of "palette"
+ * colors; its values are the final color/grayscale values, and,
+ * like r1/g1/b1[], it is _indexed_ by pc2nc[] (which is why its
+ * values come from r1/g1/b1[] and not from rmap/gmap/bmap[]).
+ *
+ * FIXME (probably): MONO() will create new duplicates; ideally should
+ * do extra round of dup-detection (and preferably collapse all
+ * remapping levels into single LUT). This stuff is a tad confusing.
+ */
+ for (i = 0; i < numuniqcols; i++)
+ remap[i] = MONO(r1[i], g1[i], b1[i]);
+
+ for (; i < 256; i++)
+ remap[i]=0; /* shouldn't be necessary, but... */
+
+ info_ptr->bit_depth = 8;
+
+ /* Note that this fails most of the time because of gamma */
+ /* (and that would be a bug: GRR FIXME) */
+ /* try to adjust to 4-bit precision grayscale */
+
+ low_precision=1;
+
+ for (i = 0; i < numuniqcols; i++) {
+ if ((remap[i] & 0x0f) * 0x11 != remap[i]) {
+ low_precision = 0;
+ break;
+ }
+ }
+
+ if (low_precision) {
+ for (i = 0; i < numuniqcols; i++) {
+ remap[i] &= 0xf;
+ }
+ info_ptr->bit_depth = 4;
+
+ /* try to adjust to 2-bit precision grayscale */
+
+ for (i = 0; i < numuniqcols; i++) {
+ if ((remap[i] & 0x03) * 0x05 != remap[i]) {
+ low_precision = 0;
+ break;
+ }
+ }
+ }
+
+ if (low_precision) {
+ for (i = 0; i < numuniqcols; i++) {
+ remap[i] &= 3;
+ }
+ info_ptr->bit_depth = 2;
+
+ /* try to adjust to 1-bit precision grayscale */
+
+ for (i = 0; i < numuniqcols; i++) {
+ if ((remap[i] & 0x01) * 0x03 != remap[i]) {
+ low_precision = 0;
+ break;
+ }
+ }
+ }
+
+ if (low_precision) {
+ for (i = 0; i < numuniqcols; 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 */
+
+// GRR FIXME: add .Xdefaults option to omit writing gamma (size, cumulative errors when editing)--alternatively, modify save box to include "omit" checkbox
+ 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");
+ /* FIXME: should be FatalError() */
+
+ 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[pc2nc[p[k]]];
+ png_write_row(png_ptr, png_line);
+ } else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+ int k;
+ for (k = 0; k < w; ++k)
+ png_line[k] = pc2nc[p[k]];
+ png_write_row(png_ptr, png_line);
+ } else { /* PNG_COLOR_TYPE_RGB */
+ 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;
+ }
+
+#ifdef PNG_NO_STDIO
+ png_set_read_fn(png_ptr, fp, png_default_read_data);
+ png_set_error_fn(png_ptr, NULL, png_xv_error, png_xv_warning);
+#else
+ png_init_io(png_ptr, fp);
+#endif
+ 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; /* used only 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 -u -r --new-file xv-3.10a.orig/xvvd.c xv-3.10a/xvvd.c
--- xv-3.10a.orig/xvvd.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvvd.c 2007-04-15 23:30:19.000000000 -0500
@@ -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 -u -r --new-file xv-3.10a.orig/xvwbmp.c xv-3.10a/xvwbmp.c
--- xv-3.10a.orig/xvwbmp.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvwbmp.c 2007-04-15 23:38:05.000000000 -0500
@@ -0,0 +1,345 @@
+/*
+ * 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)) {\
+ close(fd); \
+ return fail(st_fname, st_err); }
+#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 const char err_ueof[] = "Unexpected EOF";
+static const char err_unst[] = "Unsupported image type";
+static const char err_extf[] = "Extensions are forbidden";
+static const char err_inmb[] = "Invalid multibyte integer";
+
+static const char *st_fname;
+static const char *st_err;
+
+static int fail PARM((const char *, const 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));
+
+static void **mymem = NULL;
+static int mymems = 0;
+
+
+int LoadWBMP(fname, pinfo)
+ 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(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;
+{
+ 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;
+}
+
+
+static int fail(name, msg)
+ const char *name, *msg;
+{
+ SetISTR(ISTR_WARNING, "%s : %s", name, msg);
+ return 0;
+}
+
+
+static void write_mb(data, f)
+ 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);
+
+}
+
+
+static int read_mb(dst, fd)
+ int *dst, 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;
+}
+
+
+static int read_ext(fd, fixed)
+ 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;
+ }
+ */
+}
+
+
+static void *mymalloc(numbytes)
+ int numbytes;
+{
+ mymem = (void**)realloc(mymem, mymems+1);
+ if (!mymem)
+ FatalError("LoadWBMP: can't realloc buffer");
+ return (mymem[mymems++] = malloc(numbytes));
+}
+
+
+static 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;
+}
+
+
+static uint8 *render1(data, size, npixels)
+ uint8 *data;
+ int size, 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 -u -r --new-file xv-3.10a.orig/xvzx.c xv-3.10a/xvzx.c
--- xv-3.10a.orig/xvzx.c 1969-12-31 18:00:00.000000000 -0600
+++ xv-3.10a/xvzx.c 2007-05-13 19:53:46.000000000 -0500
@@ -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((const char *, const char *));
+
+static const 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)
+ const 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;
+}
+