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 + http://www.ibiblio.org/pub/packages/solaris/sparc/html/xv.3.10a.p19.html + - Peter Jordan + 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 + 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 + 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 + 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, () = 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-/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 , 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 , 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 +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 +# +# +# MgcSfx definition should write in one line. +# Format: +# :::::::: +# If you decide to not use preprocessor, comment style is allowed. +# # +# +# Description of your recognized image format. +# 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 instead +# of . +# * [b|l]eint16 2 byte integer of [big|little] endian. +# * [b|l]eint32 4 byte integer of [big|little] endian. +# Offset of magic number in the target image file. +# Data(magic number) of to match at . +# Suffix of filename with '.'start. +# +# Input image format type (output from ). +# * PNM (PPM, PGM, PBM) +# * AUTO Recognized by xv management, and load. +# This is different from others, because +# this write file to temporary. +# Output image format type (input to ). +# * PNM_RAW (PPM_RAW, PGM_RAW, PBM_RAW) +# * PNM_ASCII (PPM_ASCII, PGM_ASCII, PBM_ASCII) +# +# 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. +# Command to put the output image. +# * Command mast read stdin and write to stdout. +# +# 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 + +#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;iseq_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 (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 , Hewlett-Packard Laboratories, + * January 2005. + */ +#include "copyright.h" + +#define NEEDSARGS +#include "xv.h" + +#ifdef HAVE_JP2K + +#include +/* 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 [=] + 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 + +#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 + +#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 + */ + +/* + * 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$Nl9g$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 +#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$rl9g$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= '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 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%_$rnext = 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 field.\n", + fname, line_number); + def_err ++; + goto next2; + } + + if(mgcsfx_type == NULL){ + fprintf (stderr,"%s: line %d: undefined 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 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 field.\n", + fname, line_number); + def_err ++; + goto next2; + } + if((str_len = string_fin(magic))<=0){ + fprintf (stderr,"%s: line %d: invalid 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 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 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!$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$rinput_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 && inext){i++;} + } + return magic; +} + +/***************************************************/ +/* $B30It%3%^%s%I$routput_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 (curPosenPos) 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 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%-!=' ' && 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 + +#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 +#ifndef alloca +# include /* "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 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>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>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; ix-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; ix, bp->y, bp->w, bp->h)) break; + } + + if (i= 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 + +#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 + +#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 + */ + +#define PIC2_IGNORE_UNUSED_FUNCTIONS +#define NEEDSDIR + +#include "xv.h" +#include + +#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 + * 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 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; ix, bp->y, bp->w, bp->h)) break; + } + + if (ijmpbuf)) { + 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; icolor_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 + * 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)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> (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>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; +} +