mirror of
git://slackware.nl/current.git
synced 2024-12-28 09:59:53 +01:00
b76270bf9e
Wed May 19 08:58:23 UTC 2010 Slackware 13.1 x86_64 stable is released! Lots of thanks are due -- see the RELEASE_NOTES and the rest of the ChangeLog for credits. The ISOs are on their way to replication, a 6 CD-ROM 32-bit set and a dual-sided 32-bit/64-bit x86/x86_64 DVD. We are taking pre-orders now at store.slackware.com, and offering a discount if you sign up for a subscription. Consider picking up a copy to help support the project. Thanks again to the Slackware community for testing, contributing, and generally holding us to a high level of quality. :-) Enjoy!
18743 lines
527 KiB
Diff
18743 lines
527 KiB
Diff
diff -u -r --new-file xv-3.10a.orig/README.jumbo xv-3.10a/README.jumbo
|
||
--- xv-3.10a.orig/README.jumbo 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/README.jumbo 2007-05-21 00:19:20.000000000 -0500
|
||
@@ -0,0 +1,559 @@
|
||
+This is the latest version of the XV jumbo patches I originally created in
|
||
+February 2000 (but never distributed) and eventually updated and released in
|
||
+May 2004, prompted by a discussion on LWN (http://lwn.net/Articles/76391/).
|
||
+Information about the patches, updates to the patches, and the patches
|
||
+themselves can all be found here:
|
||
+
|
||
+ http://pobox.com/~newt/greg_xv.html
|
||
+ http://freshmeat.net/projects/xvjumbopatches/
|
||
+
|
||
+(Use the "Subscribe to new releases" link on the latter page if you want to
|
||
+be notified of new versions automatically; trivial registration required.)
|
||
+
|
||
+These patches incorporate all of the fix- and enhancement-patches available
|
||
+from John's XV site (http://www.trilon.com/xv/downloads.html and
|
||
+ftp://ftp.trilon.com/pub/xv/patches/), plus a number of my own fixes and
|
||
+additions (security-related and otherwise), plus quite a few from other
|
||
+people. They're still not fully complete, and it's probable they never
|
||
+will be, but I do plan to continue tinkering with them whenever the mood
|
||
+strikes--and I may even release them publicly on rare occasions. (At the
|
||
+current rate, once every few years may be the best we can hope for....)
|
||
+
|
||
+Also be aware that several other people have had the same idea over the
|
||
+years. Ones I've found, more or less by accident, include:
|
||
+
|
||
+ - Landon Curt "chongo" Noll (http://www.isthe.com/chongo/)
|
||
+ http://www.isthe.com/chongo/src/xv-patch/
|
||
+ - Mark Ashley <mark ibiblio.org>
|
||
+ http://www.ibiblio.org/pub/packages/solaris/sparc/html/xv.3.10a.p19.html
|
||
+ - Peter Jordan <pete dc.seflin.org>
|
||
+ http://www.ibiblio.org/pub/Linux/apps/graphics/viewers/X/xv-3.10a.patch.*
|
||
+ - Uwe F. Mayer (http://www.tux.org/~mayer/)
|
||
+ http://www.tux.org/~mayer/linux/book/node311.html
|
||
+ - Kurt Wall <kwall kurtwerks.com>
|
||
+ http://www.kurtwerks.com/software/xv.html
|
||
+ - Chisato Yamauchi (http://phe.phyas.aichi-edu.ac.jp/~cyamauch/index_en.html)
|
||
+ http://phe.phyas.aichi-edu.ac.jp/~cyamauch/xv.html
|
||
+ - Daisuke Yabuki <dxy optix.org>
|
||
+ http://www.optix.org/~dxy/solaris/xv/
|
||
+ - Pekoe (http://pekoe.lair.net/)
|
||
+ http://pekoe.lair.net/diary/xv.html
|
||
+ - FreeBSD FreshPorts
|
||
+ http://www.freshports.org/graphics/xv/
|
||
+ - Kyoichiro Suda <sudakyo fat.coara.or.jp>
|
||
+ http://www.coara.or.jp/~sudakyo/XV_jp.html
|
||
+
|
||
+This is not an exhaustive list (e.g., J<>rgen Grahn also had one). So far,
|
||
+most of the other patch-sets appear not to be as extensive or as up-to-date
|
||
+as my own, particularly now that the (very large) "Japanese extension" patches
|
||
+are incorporated--big thanks to Werner Fink of SuSE for that!
|
||
+
|
||
+Below I summarize the component patches that are encompassed by my jumbo
|
||
+bugfixes and jumbo enhancements patches, circa 2005. (As of 2007, they're
|
||
+distributed as a single monster-patch, and the "component patches" are now
|
||
+listed in the changelog section at the bottom of this file.) Unfortunately,
|
||
+some of my own additions never saw the light of day as standalone patches,
|
||
+but considering the number of overlaps (collisions) already implicit in the
|
||
+list, that would have been difficult to accomplish even if I'd had the time.
|
||
+
|
||
+Here's a quick guide to the "third-party" credits in the lists and changelog
|
||
+below:
|
||
+
|
||
+ AAC = Andrey A. Chernov [ache]
|
||
+ (http://cvsweb.freebsd.org/ports/graphics/xv/files/patch-ab)
|
||
+ AD = Andreas Dilger (adilger clusterfs.com)
|
||
+ AL = Alexander Lehmann (lehmann usa.net)
|
||
+ AS = Alexey Spiridonov (http://www-math.mit.edu/~lesha/)
|
||
+ AT = Anthony Thyssen (http://www.cit.gu.edu.au/~anthony/)
|
||
+ BR = Bruno Rohee (http://bruno.rohee.com/)
|
||
+ DAC = David A. Clunie (http://www.dclunie.com/xv-pcd.html)
|
||
+ EAJ = Erling A. Jacobsen (linuxcub email.dk)
|
||
+ EK = Egmont Koblinger (egmont users.sourceforge.net)
|
||
+ FG = Fabian Greffrath (fabian debian-unofficial.org)
|
||
+ GRR = Greg Roelofs (http://pobox.com/~newt/greg_contact.html)
|
||
+ GV = Guido Vollbeding (http://sylvana.net/guido/)
|
||
+ IM = IKEMOTO Masahiro (ikeyan airlab.cs.ritsumei.ac.jp)
|
||
+ JC = John Cooper (john.cooper third-harmonic.com)
|
||
+ JCE = John C. Elliott (http://www.seasip.demon.co.uk/ZX/zxdload.html)
|
||
+ JDB = John D. Baker (http://mylinuxisp.com/~jdbaker/)
|
||
+ JG = J<>rgen Grahn (jgrahn algonet.se)
|
||
+ JHB = John H. Bradley, of course (http://www.trilon.com/xv/)
|
||
+ JPD = Jean-Pierre Demailly (http://www-fourier.ujf-grenoble.fr/~demailly/)
|
||
+ JR = John Rochester (http://www.freebsd.org/cgi/query-pr.cgi?pr=2920)
|
||
+ (also http://cvsweb.freebsd.org/ports/graphics/xv/files/patch-af, -ag)
|
||
+ JRK = James Roberts Kirkpatrick (uwyo.edu)
|
||
+ JZ = Joe Zbiciak (http://spatula-city.org/~im14u2c/)
|
||
+ KS = Kyoichiro Suda (http://www.coara.or.jp/~sudakyo/XV_jp.html)
|
||
+ LCN = Landon Curt "chongo" Noll (http://www.isthe.com/chongo/)
|
||
+ LJ = Larry Jones (lawrence.jones ugs.com)
|
||
+ PBJ = Peter Jordan (http://www.ibiblio.org/pub/Linux/apps/graphics/viewers/X/)
|
||
+ PSV = Pawel S. Veselov (http://manticore.2y.net/wbmp.html)
|
||
+ RAC = Ross Combs (rocombs cs.nmsu.edu)
|
||
+ RJH = Robin Humble (http://www.cita.utoronto.ca/~rjh/)
|
||
+ SB = Sean Borman (http://www.nd.edu/~sborman/software/xvwheelmouse.html)
|
||
+ SJT = TenThumbs (tenthumbs cybernex.net)
|
||
+ SBM = Scott B. Marovich (formerly marovich hpl.hp.com)
|
||
+ TA = Tim Adye (http://hepwww.rl.ac.uk/Adye/xv-psnewstyle.html)
|
||
+ TAR = Tim Ramsey (tar pobox.com)
|
||
+ TI = Tetsuya INOUE (tin329 chino.it.okayama-u.ac.jp)
|
||
+ TO = Tavis Ormandy (taviso gentoo.org)
|
||
+ WF = Werner Fink (http://www.suse.de/~werner/)
|
||
+
|
||
+Other credits are as listed on the XV Downloads page or in the respective
|
||
+patches (e.g., the jp-extension patches or within the PNG patch).
|
||
+
|
||
+Finally, please note that these patches have not been blessed by John Bradley
|
||
+in any way (although I copied him on the May 2004 announcement and wrote to
|
||
+him again in May 2005), unless you count Debian's redistribution permission
|
||
+(Daniel Kirchheimer, 5 Dec 2005). Nor have I personally tested every change
|
||
+and feature! (See the BIG SCARY WARNING below for further caveats.) In other
|
||
+words, they're both completely unofficial and completely unguaranteed. But
|
||
+they seem to work for me. (And when they don't, I try to fix 'em--eventually,
|
||
+anyway... ;-) )
|
||
+
|
||
+Greg Roelofs, 20070520
|
||
+http://pobox.com/~newt/greg_contact.html
|
||
+
|
||
+
|
||
+How to build
|
||
+------------
|
||
+
|
||
+The following assumes you, the user, already have the libtiff,[1] libjpeg,[2]
|
||
+libpng,[3] zlib,[4] and JasPer[5] libraries downloaded, patched (if necessary),
|
||
+compiled, and installed, not to mention a C compiler and the bzip2,[6] tar,[7]
|
||
+patch,[8] and make[9] utilities. You should also have downloaded the original
|
||
+XV 3.10a source distribution from the XV Downloads page[10] and be able to edit
|
||
+its Makefile and config.h files as indicated in the INSTALL file. (Editing
|
||
+the Makefile will also allow you to disable some of the third-party libraries
|
||
+if you wish.) Finally, you should know what a Unix(-style) command line is,
|
||
+where to find one, and how to wield it with abandon (or at least with adult
|
||
+supervision)--and preferably not as the root user until the "make install"
|
||
+step. (A filesystem is a terrible thing to waste.)
|
||
+
|
||
+ [1] http://www.remotesensing.org/libtiff/
|
||
+ [2] http://www.ijg.org/
|
||
+ [3] http://www.libpng.org/pub/png/libpng.html
|
||
+ [4] http://www.zlib.net/
|
||
+ [5] http://www.ece.uvic.ca/~mdadams/jasper/
|
||
+ [6] http://sources.redhat.com/bzip2/
|
||
+ [7] http://www.gnu.org/directory/devel/specific/tar.html
|
||
+ [8] http://www.gnu.org/directory/devel/specific/patch.html
|
||
+ [9] http://www.gnu.org/directory/devel/specific/make.html
|
||
+ [10] http://www.trilon.com/xv/downloads.html#src-distrib
|
||
+
|
||
++-------------------------------------------------------------------------+
|
||
+| |
|
||
+| BIG SCARY WARNING |
|
||
+| |
|
||
+| These patches work for Greg (and parts of them reportedly work for |
|
||
+| various other people), and so far Greg's CPU still computes and his |
|
||
+| hard disks haven't been wiped. But there's no guarantee that this |
|
||
+| will be the case for you! In particular, not every incorporated patch |
|
||
+| has been explicitly tested, nor has every possible subcase of the |
|
||
+| explicitly tested subset. (Read that again; it's grammatical.) Nor |
|
||
+| are these patches officially blessed by John Bradley in any way. In |
|
||
+| other words, if you use these patches, you do so at your own risk. |
|
||
+| (Greg doesn't believe there are any serious problems remaining, but |
|
||
+| then, what programmer ever does? Bugs happen.) |
|
||
+| |
|
||
++-------------------------------------------------------------------------+
|
||
+
|
||
+Assuming you have the prerequisites out of the way and aren't scared
|
||
+off by the Big Scary Warning, here's the build procedure:
|
||
+
|
||
+ tar xvzf xv-3.10a-jumbo-patches-20070520.tar.gz
|
||
+ (or: gzip -dc xv-3.10a-jumbo-patches-20070520.tar.gz | tar xvf - )
|
||
+
|
||
+ tar xvzf xv-3.10a.tar.gz
|
||
+
|
||
+ cd xv-3.10a
|
||
+
|
||
+ patch -p1 < ../xv-3.10a-jumbo-fix-enh-patch-20070520.txt
|
||
+
|
||
+ edit Makefile and config.h as directed in INSTALL file (in particular,
|
||
+ ensure paths to external libraries and header files are correct)
|
||
+
|
||
+ make
|
||
+
|
||
+ ./xv your_favorite_image your_other_favorite_image etc.
|
||
+
|
||
+If everything seems to be working to your satisfaction, go ahead and install:
|
||
+
|
||
+ make -n install (and double-check that things will be installed
|
||
+ where you want them to be)
|
||
+
|
||
+ become root if necessary (e.g., type su)
|
||
+
|
||
+ make install
|
||
+ (or: sudo make install)
|
||
+
|
||
+That wasn't so hard, was it?
|
||
+
|
||
+
|
||
+Summary of incorporated and unincorporated patches (through 20050501)
|
||
+---------------------------------------------------------------------
|
||
+(See the ChangeLog at the bottom for more recent incorporated patches.)
|
||
+
|
||
+fixes ((*) = listed on XV Downloads page, (f) = on ftp site only):
|
||
+
|
||
+20040516:
|
||
+ - grabpatch (*) [obsoleted by new-xvgrab.c below]
|
||
+ - vispatch (*)
|
||
+ - mp-tiff-patch (*) [technically an enhancement, but JHB says...]
|
||
+ - longname.patch (*) [*SECURITY*]
|
||
+ - xpm.patch (*)
|
||
+ - deepcolor.patch (*) [slightly modified for language conformance]
|
||
+ - gifpatch (*)
|
||
+ - exceed_grab.patch (*)
|
||
+ - xv-redhat6-readme.txt (*) [slightly modified for portability]
|
||
+ - beos.patch (*) [modified for portability]
|
||
+ - croppad.patch (f)
|
||
+ - epsfpatch (f)
|
||
+ - tiff1200.patch (*)
|
||
+ - gssafer.patch (*) [*SECURITY*]
|
||
+ - new-xvgrab.c (f) [includes grabpatch but not exceed_grab.patch]
|
||
+ - xcmap.diff (AD) [part of xv-3.10a-png-1.2d.tar.gz]
|
||
+ - fixes for huge number gcc -Wall warnings--including two bugs (GRR)
|
||
+ - fix for cleandir script when no makefile exists (GRR)
|
||
+ - *SECURITY* fix for gets() in vdcomp.c (GRR, LCN vdcomp-security.patch)
|
||
+ - *SECURITY* fix for getwd() on Linux (GRR, LCN Linux-compile.patch)
|
||
+ - fix for "no fuss" Linux compiles (LCN Linux-compile.patch)
|
||
+ - partial *SECURITY* fix for mktemp() in xv.c and xvdir.c (GRR)
|
||
+ (remaining instances in xv.c (2), xvimage.c, xvfits.c, xvpds.c, xvps.c, and
|
||
+ possibly xvtiff.c--most involve system())
|
||
+ - freebsd-vdcomp-newline.patch (AAC)
|
||
+ - xv-3.10a.patch.linux (PBJ) [/bin/sh versions of cleandir, RANLIB.sh only]
|
||
+ - removed trailing white space (GRR) [purely cosmetic]
|
||
+20040523:
|
||
+ - fixed compilation error in registered versions (GRR)
|
||
+20050410:
|
||
+ - fix for YCbCr oversaturated-green bug(s) in TIFF decoder (GRR)
|
||
+ - provisional fix for contiguous tiled TIFFs with bottom-* orientation (GRR)
|
||
+ - fixes for gcc 3.3 -Wall warnings (GRR)
|
||
+ - fix for incorrect 16/24-bit display of xwd dumps (SJT)
|
||
+ - *SECURITY* fix for multiple input-validation bugs (OpenBSD/SuSE, Gentoo, GRR)
|
||
+ (this also completes the partial mktemp() security fix listed above)
|
||
+ - fix for (probable) 24-bit endianness bug in fixpix code (GRR)
|
||
+
|
||
+
|
||
+enhancements ((*) = listed on XV Downloads page, (<who>) = third-party):
|
||
+
|
||
+20040516:
|
||
+ - xv-3.10a.JPEG-patch (*)
|
||
+ (xv-3.10a.JPEG-patch.old differs only in ftp site listed in comments at top)
|
||
+ - xv-3.10a.TIFF-patch (*)
|
||
+ - xv-3.10a-png-1.2d.tar.gz (AL, AD) (*)
|
||
+ (xvjpeg.diff and xvtiff.diff ignored; xcmap.diff included in fixes)
|
||
+ - xvpng-1.2d-fix3.patch (GRR, SJT) (*)
|
||
+ - pdf.patch (*)
|
||
+ - windowid.patch + windowid.patch.readme (*)
|
||
+ - bmp32.patch (*)
|
||
+ - fixpix-20000610.tar.gz (GV)
|
||
+ (identical to 19961127 version except for README updates and new Win32 file)
|
||
+ [modified to be runtime-selectable via -/+fixpix option]
|
||
+ - browse-remember.patch (JZ)
|
||
+ - faster-smooth.patch (JZ)
|
||
+ - PAM support (GRR)
|
||
+ - PNG/GIF -ibg ("image background") transparency option (GRR)
|
||
+ (does not yet support TIFF, XPM or TGA)
|
||
+ - VersionInfo* in help screen (GRR)
|
||
+ - minor grammar/spelling fixes (GRR)
|
||
+ - floating-point support for -wait when USE_TICKS enabled (GRR)
|
||
+ - wheelmouse.patch (SB)
|
||
+ - freebsd-gravity-hints-patch (JR)
|
||
+ - xv-zx.patch (JCE)
|
||
+ - xv3.10a.wapbmp.patch (PSV)
|
||
+ - xv-3.10a-pcd.patch.20010708 (DAC)
|
||
+ - jp-ext-bzip2-1.1.patch
|
||
+ (from ftp://ftp.freebsd.org/pub/FreeBSD/ports/local-distfiles/shige/xv/)
|
||
+20050410:
|
||
+ - boosted maximum number of files from 4096 to 32768 (GRR)
|
||
+ (note that OS kernel limits may also apply; for example, in Linux see
|
||
+ MAX_ARG_PAGES in linux-<version>/include/linux/binfmts.h)
|
||
+ - xv-3.10a-bmp16.patch (KS)
|
||
+ - final-image delay (e.g., "-wait 0.2,3" : pause 3 secs on final image) (GRR)
|
||
+ - xv-numpad.patch (EK)
|
||
+ - xv-delete-is-not-backspace.patch (EK)
|
||
+ - made browser window (schnauzer) and icons configurable (AT, GRR)
|
||
+20050501:
|
||
+ - xv-3.10a-bmpfix.patch (WF) [*SECURITY*]
|
||
+ - xv310a-jp-extension-rev5.3.3.tar.gz (TI, IM, ..., WF)
|
||
+ (adds support for MAG, MAKI, Pi, PIC, and PIC2 formats[!]; "magic suffix"
|
||
+ detection/conversion; MacBinary prefixes; archives as virtual filesystems;
|
||
+ multilingual text viewer [though not Unicode]; etc.)
|
||
+ - xv-3.10a-yaos.dif (WF, TO) [*SECURITY*]
|
||
+ (fixes a number of format-string issues and system() calls)
|
||
+ - xv-3.10a.dif (WF) [*SECURITY*]
|
||
+ (fixes more format-string issues, mktemp() and open() calls, and compilation
|
||
+ warnings [mostly from jp-extension patch])
|
||
+ - xv-3.10a-jumbo-jpd_startgrab-patch-20050420.txt (JPD)
|
||
+ - PATCH.alwaysnever (LJ)
|
||
+ - PATCH.bsd (LJ)
|
||
+ - PATCH.linedraw (LJ)
|
||
+ - PATCH.multipage (LJ)
|
||
+ - PATCH.multipageGIF (LJ)
|
||
+ - PATCH.random (LJ)
|
||
+ - PATCH.stat (LJ)
|
||
+ - PATCH.thumbs (LJ)
|
||
+ - xv-startgrab-imake-hips.patch (JPD)
|
||
+ ("hips" portion only; adds support for HIPS image format[!])
|
||
+ - xv-3.10a-formatstr.patch (KS)
|
||
+ - xv-3.10a-shortsleep.patch (KS)
|
||
+ - xv-3.10a-locale-linux.patch (KS)
|
||
+ - xv-3.10a-printkey.patch (KS)
|
||
+ - xv-3.10a-sysconfdir.patch (KS)
|
||
+ - added PREFIX and DESTDIR support to Makefile (KS, GRR)
|
||
+ - xv-3.10a-xvexecpath.patch (but disabled pending fixes) (KS)
|
||
+ - xv-3.10a-zeroquit.patch (KS, GRR)
|
||
+
|
||
+[!] Note that all six of these formats may still suffer from exploitable heap
|
||
+ overflows [*SECURITY*] when decoding images with large (possibly invalid)
|
||
+ dimensions; as a result, they are DISABLED by default. (Search for "GRR
|
||
+ POSSIBLE OVERFLOW / FIXME" comments in xvmag.c, xvmaki.c, xvpi.c, xvpic.c,
|
||
+ xvpic2.c, and xvhips.c, but keep in mind that these may not be exhaustive.)
|
||
+ Users who choose to overlook these security issues can enable any or all
|
||
+ of them by editing config.h.
|
||
+
|
||
+
|
||
+not (yet?) included:
|
||
+
|
||
+ - others from http://www.coara.or.jp/~sudakyo/XV_jp.html (some are duplicates):
|
||
+ -rw-r--r-- 4644 Mar 11 2004 xv-3.10a-directory.patch
|
||
+ -rw-r--r-- 462 Mar 11 2004 xv-3.10a-dirwkey.patch
|
||
+ -rw-r--r-- 688 Mar 11 2004 xv-3.10a-docdir.patch
|
||
+ -rw-r--r-- 11952 Mar 11 2004 xv-3.10a-download-test0.patch
|
||
+ -rw-r--r-- 41786 Mar 11 2004 xv-3.10a-download-test1.patch
|
||
+ -rw-r--r-- 42397 Mar 11 2004 xv-3.10a-download-test2.patch
|
||
+ -rw-r--r-- 47679 Mar 11 2004 xv-3.10a-download-test3.patch
|
||
+ -rw-r--r-- 52745 Mar 11 2004 xv-3.10a-download-test4.patch
|
||
+ -rw-r--r-- 3423 Apr 24 2004 xv-3.10a-keyzoom.patch
|
||
+ -rw-r--r-- 12387 Mar 15 2004 xv-3.10a-menubutton.patch
|
||
+ -rw-r--r-- 1178 Apr 24 2004 xv-3.10a-noblink.patch
|
||
+ -rw-r--r-- 57092 Jul 9 2004 xv-3.10a-resolution.patch
|
||
+ -rw-r--r-- 4645 Apr 24 2004 xv-3.10a-selall.patch
|
||
+ -rw-r--r-- 702 Apr 24 2004 xv-3.10a-showlongname.patch
|
||
+ -rw-r--r-- 1205 Apr 24 2004 xv-3.10a-staytoppdir.patch
|
||
+ -rw-r--r-- 4228 Apr 24 2004 xv-3.10a-wheelmouse.patch
|
||
+ -rw-r--r-- 744 Apr 24 2004 xv-3.10a-xvbutt_wait.patch
|
||
+ -rw-r--r-- 3757 Jul 9 2004 xv-3.10a-xvscrl_button2.patch
|
||
+ -rw-r--r-- 1494 Jul 9 2004 xv-3.10a-xvscrl_wait.patch
|
||
+ -rw-r--r-- 19352 Jul 9 2004 xv-3.10a-xvzoom.patch
|
||
+
|
||
+ - xv-3.10a+jp-extension-rev5.3.3+FLmask.v2.1+png+misc.patch ["mask" support]
|
||
+
|
||
+ - xv-psnewstyle.patch (TA) [coming "soon"?]
|
||
+ - xv-3.10a.patch.linux (PBJ) [maybe use vdcomp.c changes?]
|
||
+ - xvxpm-anthony-thyssen.c (AT) ["slate grey" bug already gone?]
|
||
+ - xv-geoff-kuenning-iconsize-slideshow.patch [var. icons; full-screen slides]
|
||
+ - xv-scott-marovich-20070214-xvtiff.c.patch6.unified [TIFF CMYK support]
|
||
+
|
||
+ - stuff in xv/unsupt:
|
||
+ -rw-r--r-- 30527 Dec 22 1994 FITS.rite
|
||
+ -rw-r--r-- 49152 Dec 22 1994 FITS.tar
|
||
+ -rw-r--r-- 3753 Dec 22 1994 G3.patch1
|
||
+ -rw-r--r-- 24576 Dec 22 1994 G3.tar
|
||
+ -rw-r--r-- 1098 Dec 22 1994 INFO.cgm
|
||
+ -rw-r--r-- 1941 Dec 22 1994 README
|
||
+ -rwxr-xr-x 1059 Dec 22 1994 getweather
|
||
+ -rwxr-xr-x 2186 Dec 22 1994 getweather.ksh
|
||
+ -rw-r--r-- 856 Dec 22 1994 twm.fix
|
||
+ -rw-r--r-- 844 Dec 22 1994 vargs.c
|
||
+ -rw-r--r-- 47626 Dec 22 1994 vis
|
||
+ -rw-r--r-- 21097 Dec 22 1994 xscm
|
||
+
|
||
+
|
||
+
|
||
+not finished (and/or even started ;-) ):
|
||
+
|
||
+ - fix xvpng.c not to use direct struct access
|
||
+ - (better) fix for never-ending pile of SLOW popups when viewing TIFFs with
|
||
+ unknown tags (or truncated/corrupted images)
|
||
+ - fix for minor .Z inefficiency in xv.c ("FIXME")
|
||
+ - fix for filename entry-field mouse/cursor deficiencies
|
||
+ (positioning fixed 20070104 by Ross Combs; would like select/cut/paste, too)
|
||
+ - fix for .ppm.gz "disk leak" [can't reproduce...already fixed?]
|
||
+ (maybe occurs only if filesystem is already nearly full? bad .gz?)
|
||
+
|
||
+ - transparency support for TIFF, XPM and TGA images
|
||
+ - support for tiled background image (with transparent foreground image)
|
||
+ - MNG/JNG support
|
||
+ - SVG support
|
||
+
|
||
+
|
||
+ChangeLog
|
||
+---------
|
||
+
|
||
+ 20000220
|
||
+ original pair of jumbo patches, comprising perhaps 16 fix-patches and a
|
||
+ dozen enhancement-patches; never publicly released
|
||
+
|
||
+ 20040516
|
||
+ first public release, incorporating 25 fix-patches and 21 enhancement-
|
||
+ patches
|
||
+
|
||
+ 20040523
|
||
+ minor fix to xvctrl.c to support registered versions (GRR warnings-patch
|
||
+ was slightly overzealous); switched to tarball packaging
|
||
+
|
||
+ 20040531
|
||
+ fixed undefined CLK_TCK with gcc -ansi (enh/USE_TICKS option); made
|
||
+ libjpeg, libtiff, libpng and zlib sections of makefile more consistent
|
||
+ (enh)
|
||
+
|
||
+ 20040606
|
||
+ added freshmeat link, build instructions, and changelog to jumbo README
|
||
+ (this file)
|
||
+
|
||
+ 20050213
|
||
+ increased max number of files from 4096 to 32768 (enh)
|
||
+
|
||
+ 20050320-20050410
|
||
+ fixed two very long-standing YCbCr bugs in TIFF decoder (fix);
|
||
+ provisionally fixed bug in TIFF decoder for contiguous tiled TIFFs with
|
||
+ bottom-* orientation (fix/USE_TILED_TIFF_BOTLEFT_FIX option); fixed new
|
||
+ gcc 3.3 warnings (fix); fixed incorrect 16/24-bit display of xwd dumps
|
||
+ (fix); fixed multiple input-validation bugs (potential heap overflows)
|
||
+ and mktemp() dependencies (*SECURITY* fixes: CAN-2004-1725, CAN-2004-
|
||
+ 1726, CAN-2005-0665, CERT VU#622622, and others); added support for 16-
|
||
+ and 32-bit BMPs using bitfields "compression" (enh); fixed probable byte-
|
||
+ sex bug in 24-bit FixPix display code (enh/USE_24BIT_ENDIAN_FIX option);
|
||
+ fixed numerical-keypad NumLock behavior and delete-key behavior in file-
|
||
+ load/save window (enh); made schnauzer window and icons configurable (enh)
|
||
+
|
||
+ 20050417
|
||
+ incorporated "Japanese extension" patches, revision 5.3.3 (enh); fixed
|
||
+ additional *SECURITY* issues (format-string vulnerabilities, system()
|
||
+ and mktemp() calls, etc., but NOT heap overflows in new decoders) both
|
||
+ in existing code and in jp-extension additions (enh)
|
||
+
|
||
+ 20050425
|
||
+ added support for -startgrab option (enh); added support for a "Never"
|
||
+ button to file-overwrite popups (enh); added NetBSD and BSDI to list of
|
||
+ mkstemp()-supporting systems (enh); improved line-drawing code to set the
|
||
+ correct pixels for lines of all slopes (enh); added "Page n of m" to Info
|
||
+ window for multipage images (enh); added support for multipage (animated)
|
||
+ GIFs (enh); fixed -random support so randomized file list can be traversed
|
||
+ normally in forward or backward direction (enh); added typecasts to stat()
|
||
+ printfs for portability (enh); fixed erroneous use of "creation" time and
|
||
+ forced unlink prior to overwrite in schnauzer thumbnail code (enh); added
|
||
+ HIPS support (enh/HAVE_HIPS option)
|
||
+
|
||
+ 20050501
|
||
+ extended multipage keyboard support (PgUp/PgDn) to all windows except
|
||
+ control ("console") and directory (enh); fixed minor (non-security)
|
||
+ format-string issue in xv.c (enh); shortened delay on popup error windows
|
||
+ from 3 seconds to 1 second (enh); tweaked text-viewer localization support
|
||
+ (TV_L10N) for Linux (enh); added keyboard short cuts for Color and
|
||
+ Grayscale buttons in print dialog (enh); added support for separate "magic
|
||
+ suffix" (xv_mgcsfx) config dir (enh); added PREFIX and DESTDIR support to
|
||
+ Makefile (enh); fixed handling of zero-length files and other text-viewer
|
||
+ failures (enh)
|
||
+
|
||
+ 20050528
|
||
+ conditionally added missing alloca.h to xvpcd.c (required if alloca() is
|
||
+ a macro and alloca.h not included in stdlib.h, for example); fixed bogus
|
||
+ __S_IWRITE introduced in 20050501 release; fixed Makefile "install" target
|
||
+ (mkdir, chmod); fixed bug in MUST macro in xvwbmp.c; fixed prototype
|
||
+ warnings in xvevent.c, xvpcd.c (JRK, GRR)
|
||
+ - xv-3.10a-jimkirk-fixes.patch
|
||
+
|
||
+ 20050630
|
||
+ fixed broken mkdir(.xvpics) introduced in 20050501 release (RJH, GRR);
|
||
+ tweaked GUNZIP config for OpenBSD (GRR)
|
||
+ - xv-3.10a-xvpics-mkdir-fix.patch
|
||
+
|
||
+ 20051014
|
||
+ fixed longstanding xvevent.c typo (wasJpegUp -> wasPngUp) that caused build
|
||
+ failure if no JPEG support (TAR)
|
||
+
|
||
+ 20051019
|
||
+ fixed Darwin (Mac OS X) build error in xv.h and vdcomp.c due to lack of
|
||
+ malloc.h (JDB)
|
||
+
|
||
+ 20070210
|
||
+ fixed minor grammos (GRR); promoted PNG to first position, demoted GIF to
|
||
+ third (GRR); changed internal type of default image to PNG (GRR); increased
|
||
+ max files again, to 65536 (GRR)
|
||
+
|
||
+ 20070310
|
||
+ incorporated JPEG-2000 patch (SBM, GRR); added manual fax options for
|
||
+ unrecognized G3 images (SBM); relaxed 30-byte minimum file size (SBM)
|
||
+ - http://www.ece.uvic.ca/~mdadams/jasper/software/xv-patches
|
||
+
|
||
+ 20070318
|
||
+ incorporated 16bps raw (binary) PPM patch (define ASSUME_RAW_PPM_LSB_FIRST
|
||
+ for old behavior) (RAC, GRR); updated format list, web sites in xv man page
|
||
+ (GRR); fixed Makefile "install" target to create any necessary directories
|
||
+ (RAC, GRR); fixed GIF decoder bug (sizes of global, local color tables
|
||
+ different) (GRR)
|
||
+ - xv-ross-combs-ppm-16bps-rawbits.patch
|
||
+
|
||
+ 20070325
|
||
+ fixed invalid gamma assumption in PNG decoder (=> progressive color changes
|
||
+ over load/save cycles) (GRR)
|
||
+
|
||
+ 20070328
|
||
+ fixed animated-GIF /tmp/xvpgXXXXXX droppings (GRR)
|
||
+
|
||
+ 20070331
|
||
+ fixed PNG duplicate-palette-entries bug (GRR)
|
||
+
|
||
+ 20070415
|
||
+ incorporated EXIF-preserve patch (GHK); added missing JP2/JPC VS bits code
|
||
+ (GRR); added extended-warning options to CCOPTS (RAC); added "const" to
|
||
+ huge number of function args (RAC, GRR); made more effectively static
|
||
+ functions officially static (RAC); added mouse-clickability (but not
|
||
+ selectability) to text-entry fields (RAC); fixed window positioning (race
|
||
+ conditions?) under some virtual window managers (e.g., tvtwm) (RAC);
|
||
+ removed explicit paths for external (de)compressors (GRR, RAC)
|
||
+ - xv-geoff-kuenning-jpeg-exif-preserve.patch
|
||
+ - xv-ross-combs-20070104.diff
|
||
+
|
||
+ 20070422
|
||
+ incorporated function-key-scripts patch (see contrib/fnkey-scripts) (AS);
|
||
+ fixed man-page-section extensions ("1", not "l" or "1X") (FG); switched to
|
||
+ more sensible install paths for docs (FG); added Fedora Core build script
|
||
+ (see contrib/fedora) (JC); fixed VS to switch from move-mode to copy-mode
|
||
+ if source dir is read-only (EAJ); extended VS incremental-search mode (EAJ)
|
||
+ - xv-alexey-spiridonov-20070116-fnkey-scripts.tar.bz2
|
||
+ - xv-fabian-greffrath-20070215-debian-04-manpages.dpatch
|
||
+ - xv-fabian-greffrath-20070215-debian-03-makefiles.dpatch
|
||
+ - xv-john-cooper-Build-FC5-script.sh
|
||
+ - xv-erling-jacobsen-20060617-incr-search.patch
|
||
+
|
||
+ 20070428
|
||
+ modified install to include README.jumbo in docs (GRR); incorporated PNG
|
||
+ no-stdio patch (SBM); fixed XWD endianness support, improved performance
|
||
+ (replaces SJT 16/24-bit fix) (SBM)
|
||
+ - xv-scott-marovich-20070214-xvpng.diff
|
||
+ - xv-scott-marovich-20070214-xvxwd.c.patch
|
||
+
|
||
+ 20070506
|
||
+ added JPEG CMYK support (SBM); fixed TIFF (and others?) /tmp/xvpgXXXXXX
|
||
+ droppings (GRR); added VS clipboard support (JG)
|
||
+ - xv-scott-marovich-20070214-xvjpeg.c.patch
|
||
+ - xv-jurgen-grahn-20051127-schnauzer-clip.patch
|
||
+
|
||
+ 20070512
|
||
+ inverted handling of malloc.h header file to require NEED_MALLOC_H macro
|
||
+ for those few systems that actually need it (GRR)
|
||
+
|
||
+ 20070513
|
||
+ fixed GCC 4.1.x warnings (GRR); next round of const cleanup (GRR); fixed
|
||
+ minor TIFF memleak (GRR)
|
||
+
|
||
+ 20070514
|
||
+ fixed TIFF YCbCr reference black/white levels (SBM); added option to use
|
||
+ libjpeg YCbCr-to-RGB conversion for TIFF images (SBM, GRR)
|
||
+ - xv-scott-marovich-20070214-xvtiff.c.patch2.unified
|
||
+ - xv-scott-marovich-20070214-xvtiff.c.patch3.unified
|
||
+
|
||
+ 20070519
|
||
+ fixed handling of multi-page JPEG-compressed TIFFs (old or new) (SBM);
|
||
+ added TIFF YCbCr separated-color-plane support (may require libtiff
|
||
+ patch(es) to tif_ojpeg.c and/or tif_jpeg.c) (SBM)
|
||
+ - xv-scott-marovich-20070214-xvtiff.c.patch4.unified
|
||
+ - xv-scott-marovich-20070214-xvtiff.c.patch5.unified
|
||
+
|
||
+ 20070520
|
||
+ updated README.jumbo
|
||
diff -u -r --new-file xv-3.10a.orig/README.pcd xv-3.10a/README.pcd
|
||
--- xv-3.10a.orig/README.pcd 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/README.pcd 2001-07-08 13:21:19.000000000 -0500
|
||
@@ -0,0 +1,159 @@
|
||
+Copyright 1993-2001 David Clunie.
|
||
+
|
||
+PCD patch for XV 3.10a Release Notes 2001/07/08.
|
||
+
|
||
+See also the progress notes at the end of this file. Thanks to all those
|
||
+contributors who have substantially improved this patch.
|
||
+
|
||
+These patches allow xv to read Kodak photocd files and choose which of the
|
||
+5 available resolutions one wants to view.
|
||
+
|
||
+When a photocd file is loaded, a dialog box asks which resolution you
|
||
+would like. The visual schnauzer builds thumbnails by reading the lowest
|
||
+resolution image. The selected resolution can be selected from the
|
||
+command line with the -pcd option:
|
||
+
|
||
+ [-pcd 0|1|2|3|4]
|
||
+
|
||
+where:
|
||
+
|
||
+ 0=192*128, base/16 resolution
|
||
+ 1=384*256, base/4 resolution
|
||
+ 2=768*512, base resolution
|
||
+ 3=1536*1024, 4base resolution
|
||
+ 4=3072*2048 16base resolution.
|
||
+
|
||
+Note that the Pro format is not supported.
|
||
+
|
||
+The command line option allows loops without the dialog box popping up, eg.:
|
||
+
|
||
+ xv -pcd 1 -wloop -wait 10 *.pcd
|
||
+
|
||
+The code is pretty crude and was written quickly for a specific purpose and
|
||
+has not really been cleaned up. It is poorly structured, full of debugging
|
||
+codes and verbose comments, and there is very little attempt at optimizing
|
||
+things. No profiling has been done.
|
||
+
|
||
+There is not yet support for overview files, nor is there a facility to
|
||
+use the higher resolution chroma planes from when viewing lower resolution
|
||
+images.
|
||
+
|
||
+It's only claim to fame is that it works and produces reasonable looking
|
||
+images.
|
||
+
|
||
+The outline of this is shamelessly derived from xvpbm.c to read the
|
||
+file, and xvtiffwr.c to handle the popup window and X stuff (X never
|
||
+has been my forte !), and the PhotoCD format information (though not
|
||
+the code) was found in Hadmut Danisch's (danisch@ira.uka.de) hpcdtoppm
|
||
+program in which he has reverse engineered the format by studying
|
||
+hex dumps of PhotoCDs ! The color stuff and Huffman decding were
|
||
+extensively revised by Matthew Francey.
|
||
+
|
||
+Feel free to send me comments or improvements, or even better, more
|
||
+information about the photo CD format ... hopefully someone who really
|
||
+knows what they are doing will tidy it up or do a neater job.
|
||
+
|
||
+david (dclunie@dclunie.com)
|
||
+
|
||
+---------
|
||
+
|
||
+The trace #define in xvpcd.c is now in the right place, and the ansi
|
||
+prototype for the magnify function has been fixed. Colin made me switch to
|
||
+xvbcopy() which seems like a good idea for System V victims.
|
||
+
|
||
+---------
|
||
+
|
||
+Date: Wed, 22 Dec 1993 16:09:52 --1000
|
||
+From: colinc@fitmail.fit.qut.edu.au (Colin Canfield )
|
||
+
|
||
+I have done some more work using your patch I thought you might be intested in.
|
||
+The major change was adding a size parameter to the LoadPCD; either -1 to mean
|
||
+the popup or else the size you desired. This allows batch mode processing,
|
||
+specifically xv -pcd <size> <filename>, and the visual schnauzer can work in
|
||
+quick mode (ie. you don't have to select each image size when it is building
|
||
+the icons)
|
||
+
|
||
+I have added an xbm file for the file type but haven't drawn an icon for it,
|
||
+this is in bitmaps/br_pcd.xbm. I will just send you the new files.
|
||
+
|
||
+---------
|
||
+
|
||
+From: andrew@andrew.triumf.ca (Andrew Daviel)
|
||
+Date: 16 Feb 1995 23:32:21 GMT
|
||
+
|
||
+This is David Clunie's patch for xv-3.00 tuned a bit to work
|
||
+on xv-3.10. The code's all the same except for replacing
|
||
+"trace" with "fprintf" in xvpcd.c and adding an "unsigned" qualifier to
|
||
+keep my compiler (gcc) happy. Oh yes, changed RFT_PCD to 20 as
|
||
+John Bradley has now used 15 through 19.
|
||
+
|
||
+---------
|
||
+
|
||
+From: dclunie@flash.us.com (David A. Clunie)
|
||
+Date: Thu Jun 15 14:43:46 GMT+0300 1995
|
||
+
|
||
+Andrew's patch didn't include Colin's browser changes, so I redid the
|
||
+xv-3.10 update from scratch ... it seems pretty much the same as
|
||
+Andrew's changes. I also edited the Imakefile and Makefiles in order
|
||
+to support the PCD changes, as well as make the install process a
|
||
+little more flexible, with options to strip and set modes and so on.
|
||
+Also made RFT_PCD 25 so as not to conflict with magpic patch from Japan
|
||
+by Ikemoto Masahiro <ikeyan@airlab.cs.ritsumei.ac.jp>, and used his
|
||
+bitmap icon for pcd files.
|
||
+
|
||
+Now there are two versions of the patch, one which should be applied
|
||
+to the xv-3.10 distribution.
|
||
+
|
||
+The other should be applied to xv-3.10 AFTER Ikemoto Masahiro's
|
||
+Patch.magpic2.PhotoCD.XV319a, in order to add the browser features to
|
||
+the latter, as well as fixing a Makefile typo (was xcpcd.c not xvpcd.c)
|
||
+and including unistd.h for the SEEK_xxx constants in the magicpic
|
||
+stuff.
|
||
+
|
||
+---------
|
||
+
|
||
+Subject: Re: photo-cd patch for xv
|
||
+From: Matthew Francey <mdf@angoss.com>
|
||
+Date: Mon, 26 Mar 2001 15:37:55 +0000
|
||
+
|
||
+Attached is a revised version of xvpcd.c; the areas that I have
|
||
+re-written or changed are in a different coding style so you can tell
|
||
+what has changed. The GNU 'indent' program can be run against the file
|
||
+to enforce a consistent style ..
|
||
+
|
||
+Here is what I've done though:
|
||
+
|
||
+a) huffman table reader re-written, because it would fail on some
|
||
+ photocd files with "unusual" huffman codes.
|
||
+
|
||
+b) the huffman-coded corrections are now properly applied
|
||
+
|
||
+c) the corrections can sometimes over or underflow; clipping has been
|
||
+ introduced and effectively fixes the problem, but I suspect that
|
||
+ there is something deeper going on.
|
||
+
|
||
+d) the "official" YCC->sRGB transform is done. a "beyond 100% white"
|
||
+ mapping table was snarfed from ImageMagick. an option for using a
|
||
+ flat linear LUT was added -- this can make somewhat over-exposed images
|
||
+ look alot nicer.
|
||
+
|
||
+e) there were strange problems where the code wouldn't be able to find
|
||
+ the huffman tables and data for the 16base image (the bit-buffering
|
||
+ code was starting mid-sector, instead of at a sector boundary). Looking
|
||
+ at a pcd file with a hex editor suggests to me that it is possible to
|
||
+ just skip directly to these huffman tables -- no special "+12" and such
|
||
+ constants necessary. But I haven't tried this yet.
|
||
+
|
||
+The results: I've been able to read about 50 or 60 .pcd files [scattered
|
||
+in age from 6 years old to scans done last week] with this code without
|
||
+incident. Image quality at the high resolution is excellent. Even the
|
||
+trivial amount of LUT control is useful when dealing with over-exposed
|
||
+images.
|
||
+
|
||
+If I get around to it: finer LUT control to take advantage of the
|
||
+slightly extended dynamic range of PhotoCD scans, especially in regards to
|
||
+dark or somewhat underexposed scenes.
|
||
+
|
||
+
|
||
+
|
||
+
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_bzip2 xv-3.10a/bits/br_bzip2
|
||
--- xv-3.10a.orig/bits/br_bzip2 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_bzip2 1998-04-12 21:23:39.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_bzip2_width 48
|
||
+#define br_bzip2_height 48
|
||
+static unsigned char br_bzip2_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x7c, 0xbe, 0x3d, 0x0e, 0x02, 0x20, 0xfc, 0xbe, 0x7d, 0x1f, 0x02,
|
||
+ 0x20, 0xcc, 0xb0, 0x6d, 0x1b, 0x02, 0x20, 0xcc, 0x98, 0x6d, 0x1b, 0x02,
|
||
+ 0x20, 0xfc, 0x98, 0x6d, 0x18, 0x02, 0x20, 0x7c, 0x8c, 0x7d, 0x0c, 0x02,
|
||
+ 0x20, 0xcc, 0x8c, 0x3d, 0x0e, 0x02, 0x20, 0xcc, 0x84, 0x0d, 0x06, 0x02,
|
||
+ 0x20, 0xcc, 0x86, 0x0d, 0x03, 0x02, 0x20, 0xfc, 0xbe, 0x0d, 0x1f, 0x02,
|
||
+ 0x20, 0x7c, 0xbe, 0x0d, 0x1f, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_jp2 xv-3.10a/bits/br_jp2
|
||
--- xv-3.10a.orig/bits/br_jp2 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_jp2 2005-05-09 00:00:27.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_jp2_width 48
|
||
+#define br_jp2_height 48
|
||
+static unsigned char br_jp2_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0xfb, 0xf1, 0x01, 0x02,
|
||
+ 0x20, 0x00, 0xfb, 0xfb, 0x03, 0x02, 0x20, 0x00, 0x1b, 0x1b, 0x03, 0x02,
|
||
+ 0x20, 0x00, 0x1b, 0x1b, 0x00, 0x02, 0x20, 0x00, 0x1b, 0x1b, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x9b, 0x1b, 0x00, 0x02, 0x20, 0x00, 0xfb, 0x19, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0xfb, 0x18, 0x00, 0x02, 0x20, 0x18, 0x1b, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0x18, 0x1b, 0x18, 0x00, 0x02, 0x20, 0xb8, 0x1b, 0x18, 0x03, 0x02,
|
||
+ 0x20, 0xf0, 0x19, 0xf8, 0x03, 0x02, 0x20, 0xe0, 0x18, 0xf0, 0x01, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_jpc xv-3.10a/bits/br_jpc
|
||
--- xv-3.10a.orig/bits/br_jpc 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_jpc 2005-05-09 00:00:27.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_jpc_width 48
|
||
+#define br_jpc_height 48
|
||
+static unsigned char br_jpc_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0xfb, 0xf1, 0x01, 0x02,
|
||
+ 0x20, 0x00, 0xfb, 0xfb, 0x03, 0x02, 0x20, 0x00, 0x1b, 0x1b, 0x03, 0x02,
|
||
+ 0x20, 0x00, 0x1b, 0x03, 0x03, 0x02, 0x20, 0x00, 0x1b, 0x03, 0x03, 0x02,
|
||
+ 0x20, 0x00, 0x9b, 0x83, 0x01, 0x02, 0x20, 0x00, 0xfb, 0xc1, 0x01, 0x02,
|
||
+ 0x20, 0x00, 0xfb, 0xe0, 0x00, 0x02, 0x20, 0x18, 0x1b, 0x70, 0x00, 0x02,
|
||
+ 0x20, 0x18, 0x1b, 0x38, 0x00, 0x02, 0x20, 0xb8, 0x1b, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0xf0, 0x19, 0xf8, 0x03, 0x02, 0x20, 0xe0, 0x18, 0xf8, 0x03, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_mag xv-3.10a/bits/br_mag
|
||
--- xv-3.10a.orig/bits/br_mag 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_mag 2005-04-17 16:04:22.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_mag_width 48
|
||
+#define br_mag_height 48
|
||
+static unsigned char br_mag_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x0c, 0x86, 0xc1, 0x0f, 0x02,
|
||
+ 0x20, 0x0c, 0xc6, 0xe3, 0x1f, 0x02, 0x20, 0x1c, 0xe7, 0x67, 0x18, 0x02,
|
||
+ 0x20, 0x1c, 0x77, 0x6e, 0x18, 0x02, 0x20, 0xbc, 0x37, 0x6c, 0x00, 0x02,
|
||
+ 0x20, 0xbc, 0x37, 0x6c, 0x00, 0x02, 0x20, 0xec, 0x36, 0x6c, 0x1e, 0x02,
|
||
+ 0x20, 0xec, 0xf6, 0x6f, 0x1e, 0x02, 0x20, 0x4c, 0xf6, 0x6f, 0x18, 0x02,
|
||
+ 0x20, 0x4c, 0x36, 0x6c, 0x18, 0x02, 0x20, 0x0c, 0x36, 0x6c, 0x18, 0x02,
|
||
+ 0x20, 0x0c, 0x36, 0xec, 0x1f, 0x02, 0x20, 0x0c, 0x36, 0xcc, 0x0f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_maki xv-3.10a/bits/br_maki
|
||
--- xv-3.10a.orig/bits/br_maki 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_maki 2005-04-17 16:04:22.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_maki_width 48
|
||
+#define br_maki_height 48
|
||
+static unsigned char br_maki_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x83, 0x61, 0x18, 0x33, 0x02,
|
||
+ 0x20, 0x83, 0xf1, 0x98, 0x33, 0x02, 0x20, 0xc7, 0xf9, 0x99, 0x31, 0x02,
|
||
+ 0x20, 0xc7, 0x9d, 0xdb, 0x30, 0x02, 0x20, 0xef, 0x0d, 0xfb, 0x30, 0x02,
|
||
+ 0x20, 0xef, 0x0d, 0x7b, 0x30, 0x02, 0x20, 0xbb, 0x0d, 0x7b, 0x30, 0x02,
|
||
+ 0x20, 0xbb, 0xfd, 0xdb, 0x30, 0x02, 0x20, 0x93, 0xfd, 0xdb, 0x30, 0x02,
|
||
+ 0x20, 0x93, 0x0d, 0x9b, 0x31, 0x02, 0x20, 0x83, 0x0d, 0x9b, 0x31, 0x02,
|
||
+ 0x20, 0x83, 0x0d, 0x1b, 0x33, 0x02, 0x20, 0x83, 0x0d, 0x1b, 0x33, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_mgcsfx xv-3.10a/bits/br_mgcsfx
|
||
--- xv-3.10a.orig/bits/br_mgcsfx 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_mgcsfx 2005-04-17 16:04:22.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_mgcsfx_width 48
|
||
+#define br_mgcsfx_height 48
|
||
+static unsigned char br_mgcsfx_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x3c, 0xcf, 0x71, 0x00, 0x02,
|
||
+ 0x20, 0x6c, 0x61, 0xda, 0x00, 0x02, 0x20, 0x6c, 0x67, 0xd8, 0x1e, 0x02,
|
||
+ 0x20, 0x3c, 0x61, 0xd8, 0x1e, 0x02, 0x20, 0x6c, 0x61, 0xda, 0x00, 0x02,
|
||
+ 0x20, 0x6c, 0xcf, 0x71, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x4e, 0x7a, 0xef, 0x3d, 0x02, 0x20, 0xd3, 0x32, 0x68, 0x6c, 0x02,
|
||
+ 0x20, 0xc3, 0x32, 0xe4, 0x6c, 0x02, 0x20, 0x5b, 0x33, 0x62, 0x6c, 0x02,
|
||
+ 0x20, 0x53, 0x33, 0x61, 0x6c, 0x02, 0x20, 0x4e, 0x7a, 0xef, 0x3d, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_pcd xv-3.10a/bits/br_pcd
|
||
--- xv-3.10a.orig/bits/br_pcd 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_pcd 1995-06-15 23:31:53.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_pcd_width 48
|
||
+#define br_pcd_height 48
|
||
+static unsigned char br_pcd_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x67, 0x00, 0xe0, 0x1c, 0x02,
|
||
+ 0x20, 0x6f, 0x00, 0xf0, 0x3d, 0x02, 0x20, 0x6b, 0x00, 0xb0, 0x2d, 0x02,
|
||
+ 0x20, 0x6b, 0x00, 0x33, 0x2c, 0x02, 0x20, 0x6b, 0x00, 0x33, 0x2c, 0x02,
|
||
+ 0x20, 0xeb, 0x98, 0x37, 0x2c, 0x02, 0x20, 0xef, 0xbd, 0x37, 0x2c, 0x02,
|
||
+ 0x20, 0x67, 0x2d, 0x33, 0x2c, 0x02, 0x20, 0x63, 0x2d, 0x33, 0x2c, 0x02,
|
||
+ 0x20, 0x63, 0x2d, 0x33, 0x2c, 0x02, 0x20, 0x63, 0x2d, 0xb3, 0x2d, 0x02,
|
||
+ 0x20, 0x63, 0x3d, 0xf7, 0x3d, 0x02, 0x20, 0x63, 0x19, 0xe6, 0x1c, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_pi xv-3.10a/bits/br_pi
|
||
--- xv-3.10a.orig/bits/br_pi 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_pi 2005-04-17 16:04:22.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_pi_width 48
|
||
+#define br_pi_height 48
|
||
+static unsigned char br_pi_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x80, 0x1f, 0x7e, 0x00, 0x02,
|
||
+ 0x20, 0x80, 0x3f, 0x7e, 0x00, 0x02, 0x20, 0x80, 0x31, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0x80, 0x31, 0x18, 0x00, 0x02, 0x20, 0x80, 0x31, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0x80, 0x39, 0x18, 0x00, 0x02, 0x20, 0x80, 0x1f, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0x80, 0x0f, 0x18, 0x00, 0x02, 0x20, 0x80, 0x01, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0x80, 0x01, 0x18, 0x00, 0x02, 0x20, 0x80, 0x01, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0x80, 0x01, 0x7e, 0x00, 0x02, 0x20, 0x80, 0x01, 0x7e, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_pic xv-3.10a/bits/br_pic
|
||
--- xv-3.10a.orig/bits/br_pic 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_pic 2005-04-17 16:04:22.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_pic_width 48
|
||
+#define br_pic_height 48
|
||
+static unsigned char br_pic_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xf0, 0xf3, 0xf3, 0x01, 0x02,
|
||
+ 0x20, 0xf0, 0xf7, 0xfb, 0x03, 0x02, 0x20, 0x30, 0xc6, 0x18, 0x03, 0x02,
|
||
+ 0x20, 0x30, 0xc6, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc6, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0x30, 0xc7, 0x18, 0x00, 0x02, 0x20, 0xf0, 0xc3, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0xf0, 0xc1, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc0, 0x18, 0x00, 0x02,
|
||
+ 0x20, 0x30, 0xc0, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc0, 0x18, 0x03, 0x02,
|
||
+ 0x20, 0x30, 0xf0, 0xfb, 0x03, 0x02, 0x20, 0x30, 0xf0, 0xf3, 0x01, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_pic2 xv-3.10a/bits/br_pic2
|
||
--- xv-3.10a.orig/bits/br_pic2 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_pic2 2005-04-17 16:04:22.000000000 -0500
|
||
@@ -0,0 +1,27 @@
|
||
+#define br_pic2_width 48
|
||
+#define br_pic2_height 48
|
||
+static unsigned char br_pic2_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x3f, 0x3f, 0x1f, 0x1f, 0x02,
|
||
+ 0x20, 0x7f, 0xbf, 0xbf, 0x3f, 0x02, 0x20, 0x63, 0x8c, 0xb1, 0x31, 0x02,
|
||
+ 0x20, 0x63, 0x8c, 0x01, 0x30, 0x02, 0x20, 0x63, 0x8c, 0x01, 0x30, 0x02,
|
||
+ 0x20, 0x73, 0x8c, 0x01, 0x30, 0x02, 0x20, 0x3f, 0x8c, 0x01, 0x18, 0x02,
|
||
+ 0x20, 0x1f, 0x8c, 0x01, 0x0c, 0x02, 0x20, 0x03, 0x8c, 0x01, 0x06, 0x02,
|
||
+ 0x20, 0x03, 0x8c, 0x01, 0x03, 0x02, 0x20, 0x03, 0x8c, 0xb1, 0x01, 0x02,
|
||
+ 0x20, 0x03, 0xbf, 0xbf, 0x3f, 0x02, 0x20, 0x03, 0x3f, 0x9f, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_png xv-3.10a/bits/br_png
|
||
--- xv-3.10a.orig/bits/br_png 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_png 1996-06-13 16:32:08.000000000 -0500
|
||
@@ -0,0 +1,28 @@
|
||
+#define br_png_width 48
|
||
+#define br_png_height 48
|
||
+static unsigned char br_png_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0xf8, 0x19, 0xc3, 0x07, 0x02, 0x20, 0x18, 0x3b, 0x63, 0x0c, 0x02,
|
||
+ 0x20, 0x18, 0x3b, 0x33, 0x00, 0x02, 0x20, 0x18, 0x5b, 0x33, 0x00, 0x02,
|
||
+ 0x20, 0xf8, 0x59, 0x33, 0x0f, 0x02, 0x20, 0x18, 0x98, 0x33, 0x0c, 0x02,
|
||
+ 0x20, 0x18, 0x98, 0x33, 0x0c, 0x02, 0x20, 0x18, 0x18, 0x63, 0x0c, 0x02,
|
||
+ 0x20, 0x18, 0x18, 0xc3, 0x0b, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
|
||
+ };
|
||
diff -u -r --new-file xv-3.10a.orig/bits/br_zx xv-3.10a/bits/br_zx
|
||
--- xv-3.10a.orig/bits/br_zx 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/bits/br_zx 1998-08-06 15:00:03.000000000 -0500
|
||
@@ -0,0 +1,28 @@
|
||
+#define br_zx_width 48
|
||
+#define br_zx_height 48
|
||
+static unsigned char br_zx_bits[] = {
|
||
+ 0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x7f, 0xce, 0x01, 0x0e, 0x02, 0x20, 0x61, 0x84, 0x00, 0x11, 0x02,
|
||
+ 0x20, 0x30, 0x48, 0x00, 0x10, 0x02, 0x20, 0x18, 0x38, 0x10, 0x08, 0x02,
|
||
+ 0x20, 0x0c, 0x30, 0x10, 0x0e, 0x02, 0x20, 0x06, 0x68, 0x7c, 0x10, 0x02,
|
||
+ 0x20, 0x03, 0x48, 0x10, 0x10, 0x02, 0x20, 0x41, 0x84, 0x10, 0x11, 0x02,
|
||
+ 0x20, 0x7f, 0xce, 0x01, 0x0e, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xff, 0xff, 0xff, 0xff, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x40, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x10, 0x02, 0x20, 0x00, 0x00, 0x00, 0x08, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0x84, 0x03, 0x20, 0x00, 0x00, 0x00, 0xc2, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x20, 0x00, 0x00, 0x80, 0xf0, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x40, 0x78, 0x02, 0x20, 0x00, 0x00, 0x20, 0x3c, 0x02,
|
||
+ 0x20, 0x00, 0x00, 0x10, 0x1e, 0x02, 0x20, 0x00, 0x00, 0x08, 0x0f, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0x84, 0x87, 0x03, 0x20, 0x00, 0x00, 0xc2, 0xc3, 0x03,
|
||
+ 0x20, 0x00, 0x00, 0xe1, 0xe1, 0x03, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
|
||
+ };
|
||
diff -u -r --new-file xv-3.10a.orig/contrib/fedora/Build-FC5 xv-3.10a/contrib/fedora/Build-FC5
|
||
--- xv-3.10a.orig/contrib/fedora/Build-FC5 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/contrib/fedora/Build-FC5 2006-06-01 10:12:47.000000000 -0500
|
||
@@ -0,0 +1,56 @@
|
||
+#!/bin/bash
|
||
+#
|
||
+# prep and build XV for FC5
|
||
+#
|
||
+# adapted from Slackware 10.2 -- john.cooper@third-harmonic.com
|
||
+#
|
||
+
|
||
+if [ ${1}foo == "__LOGGED__foo" ]; then
|
||
+ shift
|
||
+else
|
||
+ for i in `seq 0 9`
|
||
+ do
|
||
+ if [ -e ${0}.log.$((9-i)) ]; then
|
||
+ mv ${0}.log.$((9-i)) ${0}.log.$((9-i+1))
|
||
+ fi
|
||
+ done
|
||
+
|
||
+ exec $0 __LOGGED__ $@ 2>&1 | tee $BUILDDIR/$0.log.0
|
||
+ exit $?
|
||
+fi
|
||
+
|
||
+SOURCE=`pwd`
|
||
+if [ "$BUILD" = "" ]; then
|
||
+ BUILD=./build
|
||
+fi
|
||
+
|
||
+if [ ! -d $BUILD ]; then
|
||
+ mkdir -p $BUILD
|
||
+fi
|
||
+
|
||
+PFLAGS="--verbose --backup --suffix=.orig"
|
||
+
|
||
+function bail()
|
||
+ {
|
||
+ echo "$0: failed $1"
|
||
+ exit 1
|
||
+ }
|
||
+
|
||
+cd $BUILD
|
||
+rm -rf xv-3.10
|
||
+tar xzvf $SOURCE/xv-3.10.tar.gz
|
||
+cd xv-3.10
|
||
+zcat $SOURCE/xv-3.10a.patch.gz | patch -p0 $PFLAGS || \
|
||
+ bail $SOURCE/xv-3.10a.patch.gz
|
||
+bzcat $SOURCE/xv-3.10a-jumbo-fix-patch-20050410.txt.bz2 | patch -p1 $PFLAGS || \
|
||
+ bail $SOURCE/xv-3.10a-jumbo-fix-patch-20050410.txt.bz2
|
||
+bzcat $SOURCE/xv-3.10a-jumbo-enh-patch-20050501.txt.bz2 | patch -p1 $PFLAGS || \
|
||
+ bail $SOURCE/xv-3.10a-jumbo-enh-patch-20050501.txt.bz2
|
||
+zcat $SOURCE/xv.prefix.diff.gz | patch -p1 $PFLAGS || \
|
||
+ bail $SOURCE/xv.prefix.diff.gz
|
||
+make -f Makefile.std || bail make
|
||
+strip --strip-unneeded bggen vdcomp xcmap xv xvpictoppm || bail strip
|
||
+
|
||
+exit $?
|
||
+
|
||
+# vi:set ts=4:
|
||
diff -u -r --new-file xv-3.10a.orig/contrib/fedora/README xv-3.10a/contrib/fedora/README
|
||
--- xv-3.10a.orig/contrib/fedora/README 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/contrib/fedora/README 2006-06-01 10:12:47.000000000 -0500
|
||
@@ -0,0 +1,16 @@
|
||
+Greg,
|
||
+ After winding up in dark lonely places trying to
|
||
+get xv-3.10a to build on FC5 I suspected I was missing
|
||
+something. Then I happened on your patch manifest
|
||
+in Slackware 10.2.
|
||
+
|
||
+I bandsawed the script a bit to use in propagating XV
|
||
+to a handful of personal FC5 machines. Attached for
|
||
+reference.
|
||
+
|
||
+Thanks for your effort!
|
||
+
|
||
+-john
|
||
+
|
||
+--
|
||
+john.cooper@third-harmonic.com
|
||
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/README xv-3.10a/contrib/fnkey-scripts/README
|
||
--- xv-3.10a.orig/contrib/fnkey-scripts/README 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/contrib/fnkey-scripts/README 2007-01-16 02:41:51.000000000 -0600
|
||
@@ -0,0 +1,111 @@
|
||
+-- License and Disclaimer --
|
||
+
|
||
+This patch & script package was written by Alexey Spiridonov, and is
|
||
+licensed under the GNU GPLv2. There is NO WARRANTY.
|
||
+
|
||
+XV is copyrighted by John Bradley.
|
||
+
|
||
+-- What is this? --
|
||
+
|
||
+This is a small patch for XV that allows you to run scripts by pressing
|
||
+a key from F1 through F12 (or more, just change 12 to your number in the
|
||
+patch file).
|
||
+
|
||
+The patch enables a number of useful features. Here is a my set-up:
|
||
+
|
||
+F1: Losslessly rotate JPEG 90 degrees to the right.
|
||
+F2: Losslessly rotate JPEG 90 degrees to the left.
|
||
+
|
||
+F3: Print the current selection rectangle (on the terminal where xv was
|
||
+ launched). This is useful for quickly recording a bunch of positions in
|
||
+ an image. Use case:
|
||
+ I'm annotating face positions.
|
||
+ 1) Select Joe in picture, hit F3, type "Joe" in the terminal.
|
||
+ 2) Select Jane in the picture, ...
|
||
+ ...
|
||
+ n) Copy the text visible in the terminal, and paste it into the
|
||
+ JPEG comment.
|
||
+ Of course, i would write a more convenient script if I annotated faces
|
||
+ with any any frequency.
|
||
+
|
||
+F4: Edit JPEG comment (I use it for annotations/tags).
|
||
+
|
||
+F5: Log a 'losslessly rotate right' command for batch processing. This
|
||
+ writes the rotation command for the current file into a shell script
|
||
+ somewhere ("~/photos/bin/rotscript" by default). This is great for
|
||
+ slower computers because you don't have to wait for each image to
|
||
+ rotate; instead, you just rotate them all at once by running the
|
||
+ resulting script.
|
||
+F6: Log a 'losslessly rotate left' batch command.
|
||
+
|
||
+F8: Crop image on disk, but back-up the uncropped version. You can make
|
||
+ a succession of crops this way, with a backup made at every step.
|
||
+ This wastes disk space, so be sure to clean up once you get a crop you
|
||
+ like.
|
||
+F7: Undo the last crop done on this image. This can be repeated until you're
|
||
+ back at the original.
|
||
+
|
||
+-- Installation --
|
||
+
|
||
+I'll tell you how to get the set-up I described above. Of course, you can
|
||
+customize it to your heart's content.
|
||
+
|
||
+(( 1 ))
|
||
+
|
||
+Go to:
|
||
+
|
||
+ http://www.sonic.net/~roelofs/greg_xv.html
|
||
+
|
||
+and follow the XV install instructions there. If you are okay with
|
||
+reading shell scripts, you might also give this a shot:
|
||
+
|
||
+ http://sources.gentoo.org/viewcvs.py/*checkout*/gentoo-x86/media-gfx/xv/xv-3.10a-r12.ebuild
|
||
+
|
||
+When you're ready to type "make install", do the following to apply my patch:
|
||
+
|
||
+ $ cd WHEREVER_YOU_COMPILED_XV
|
||
+ $ patch -p1 --dry-run < PATH/TO/xv-3.10a-fkey-command-patch.greg-xv
|
||
+
|
||
+Hopefully, the above command won't complain; if it does, Greg Roelofs
|
||
+probably changed his patchset, and my patch has become out of date -- let me
|
||
+know. If that went well, run:
|
||
+
|
||
+ $ patch -p1 < PATH/TO/xv-3.10a-fkey-command-patch.greg-xv
|
||
+
|
||
+Now, simply recompile and install as described in the other instructions.
|
||
+
|
||
+(( 2 ))
|
||
+
|
||
+Copy 'jpegcrop.sh', 'jpegeditcom.sh', 'jpegundocrop.sh', 'jpegrot.sh',
|
||
+'jpeglogrot.sh' to some convenient directory.
|
||
+
|
||
+Suggestions: ~/photos/bin, /usr/local/bin, etc...
|
||
+
|
||
+Edit 'jpeglogrot.sh' and 'jpegeditcom.sh'. In the former, you need to
|
||
+customize the path to 'jpegrot.sh'. In the latter, you should make set
|
||
+your favorite editor. The spots to customize are marked as such.
|
||
+
|
||
+(( 3 ))
|
||
+
|
||
+Open .Xdefaults in your favorite text editor, and paste the following lines
|
||
+there:
|
||
+
|
||
+xv.F1command: ~/photos/bin/jpegrot.sh 90 %s
|
||
+xv.F2command: ~/photos/bin/jpegrot.sh 270 %s
|
||
+xv.F3command: @echo "The selection rect for '%s' is at (%d, %d) of size %dx%d."
|
||
+xv.F4command: @~/photos/bin/jpegeditcom.sh %s &
|
||
+xv.F5command: @~/photos/bin/jpeglogrot.sh 90 %s
|
||
+xv.F6command: @~/photos/bin/jpeglogrot.sh 270 %s
|
||
+xv.F7command: ~/photos/bin/jpegundocrop.sh %s
|
||
+xv.F8command: ~/photos/bin/jpegcrop.sh %s %d %d %d %d
|
||
+
|
||
+Change '~/photos/bin/' to the directory you chose in (( 2 )). In case you're
|
||
+wondering what the '@' symbol means, it tells XV not to reload the file
|
||
+after running this command. The default is to reload the file.
|
||
+
|
||
+-- Apologies --
|
||
+
|
||
+I didn't get a chance to run through the above instructions and check
|
||
+that they work. I know they're right in spirit, but I might've made a typo
|
||
+or two. Even if it's obvious to you, would you please let me know by writing
|
||
+to lesha at mit dot edu?
|
||
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpegcrop.sh xv-3.10a/contrib/fnkey-scripts/jpegcrop.sh
|
||
--- xv-3.10a.orig/contrib/fnkey-scripts/jpegcrop.sh 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/contrib/fnkey-scripts/jpegcrop.sh 2006-03-11 21:30:03.000000000 -0600
|
||
@@ -0,0 +1,33 @@
|
||
+#!/bin/bash
|
||
+FILE=$1
|
||
+WIDTH=$4
|
||
+HEIGHT=$5
|
||
+XPOS=$2
|
||
+YPOS=$3
|
||
+if [[ $XPOS -lt 0 ]]; then
|
||
+ echo "Negative x position $XPOS converted to zero, width adjusted."
|
||
+ WIDTH=$((WIDTH+XPOS))
|
||
+ XPOS=0
|
||
+fi
|
||
+if [[ $YPOS -lt 0 ]]; then
|
||
+ echo "Negative y position $YPOS converted to zero, height adjusted."
|
||
+ HEIGHT=$((HEIGHT+YPOS))
|
||
+ YPOS=0
|
||
+fi
|
||
+if [[ $(($WIDTH+$HEIGHT)) == 0 ]]; then
|
||
+ echo "Refusing to crop $FILE with an empty rectangle."
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+TMPFILE=`mktemp $FILE.tmp-jpeg-rot-XXXXXXXX`
|
||
+if jpegtran -optimize -progressive -crop ${WIDTH}x${HEIGHT}+${XPOS}+${YPOS} \
|
||
+ -copy all $FILE > $TMPFILE; then
|
||
+ COUNT=`echo $FILE-uncropped | wc -c`
|
||
+ NEXT=$((`ls $FILE-uncropped* | cut -b $COUNT- | grep '^[0-9]*$' \
|
||
+ | sed 's/^0*/'/ | sort -n | tail -n 1`+1))
|
||
+ # the targets shouldn't exist, but -i just in case
|
||
+ mv -i $FILE $FILE-uncropped$NEXT
|
||
+ mv -i $TMPFILE $FILE
|
||
+else
|
||
+ rm $TMPFILE
|
||
+fi
|
||
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpegeditcom.sh xv-3.10a/contrib/fnkey-scripts/jpegeditcom.sh
|
||
--- xv-3.10a.orig/contrib/fnkey-scripts/jpegeditcom.sh 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/contrib/fnkey-scripts/jpegeditcom.sh 2007-01-16 00:23:04.000000000 -0600
|
||
@@ -0,0 +1,12 @@
|
||
+#!/bin/bash
|
||
+CFILE=`mktemp $1.tmp-jpeg-comments-XXXXXXXX`
|
||
+TMPFILE=`mktemp $1.tmp-jpeg-XXXXXXXX`
|
||
+rdjpgcom $1 > $CFILE
|
||
+INITIAL=`md5sum $CFILE`
|
||
+xterm -e "$EDITOR" "$CFILE" # customize your editor here
|
||
+MODIFIED=`md5sum $CFILE`
|
||
+if [[ "$INITIAL" != "$MODIFIED" ]]; then
|
||
+ mv $1 $TMPFILE
|
||
+ wrjpgcom -replace -cfile $CFILE $TMPFILE > $1
|
||
+fi
|
||
+rm $TMPFILE $CFILE $CFILE~
|
||
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpeglogrot.sh xv-3.10a/contrib/fnkey-scripts/jpeglogrot.sh
|
||
--- xv-3.10a.orig/contrib/fnkey-scripts/jpeglogrot.sh 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/contrib/fnkey-scripts/jpeglogrot.sh 2007-01-16 00:55:18.000000000 -0600
|
||
@@ -0,0 +1,10 @@
|
||
+#!/bin/bash
|
||
+curdir="`pwd`"
|
||
+LOG=~/photos/bin/rotscript # customize your install dir here
|
||
+if [[ ! -e "$LOG" ]]; then
|
||
+ echo '#!/bin/bash' >> "$LOG"
|
||
+ chmod u+x "$LOG"
|
||
+fi
|
||
+echo "# following entry made on `date`" >> "$LOG"
|
||
+# also customize the following line
|
||
+echo ~/photos/bin/jpegrot \""$1"\" \""$curdir/$2"\" >> "$LOG"
|
||
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpegrot.sh xv-3.10a/contrib/fnkey-scripts/jpegrot.sh
|
||
--- xv-3.10a.orig/contrib/fnkey-scripts/jpegrot.sh 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/contrib/fnkey-scripts/jpegrot.sh 2006-07-18 23:10:43.000000000 -0500
|
||
@@ -0,0 +1,7 @@
|
||
+#!/bin/bash
|
||
+TMPFILE="`mktemp "$2".tmp-jpeg-rot-XXXXXXXX`"
|
||
+if jpegtran -perfect -optimize -progressive -rotate "$1" -copy all "$2" > "$TMPFILE"; then
|
||
+ mv "$TMPFILE" "$2"
|
||
+else
|
||
+ rm "$TMPFILE"
|
||
+fi
|
||
diff -u -r --new-file xv-3.10a.orig/contrib/fnkey-scripts/jpegundocrop.sh xv-3.10a/contrib/fnkey-scripts/jpegundocrop.sh
|
||
--- xv-3.10a.orig/contrib/fnkey-scripts/jpegundocrop.sh 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/contrib/fnkey-scripts/jpegundocrop.sh 2006-03-11 21:30:04.000000000 -0600
|
||
@@ -0,0 +1,8 @@
|
||
+#!/bin/bash
|
||
+FILE=$1
|
||
+COUNT=`echo $FILE-uncropped | wc -c`
|
||
+LATEST=$((`ls $FILE-uncropped* | cut -b $COUNT- | grep '^[0-9]*$' \
|
||
+ | sed 's/^0*/'/ | sort -n | tail -n 1`))
|
||
+if [[ -f $FILE-uncropped$LATEST ]]; then
|
||
+ mv $FILE-uncropped$LATEST $FILE
|
||
+fi
|
||
diff -u -r --new-file xv-3.10a.orig/tiff/RANLIB.sh xv-3.10a/tiff/RANLIB.sh
|
||
--- xv-3.10a.orig/tiff/RANLIB.sh 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/tiff/RANLIB.sh 2004-05-11 01:31:38.000000000 -0500
|
||
@@ -0,0 +1,22 @@
|
||
+#!/bin/sh -f
|
||
+#
|
||
+# tests to see if the program 'ranlib' exists. If it does, runs ranlib on
|
||
+# the first argument (a library name). Otherwise, does nothing, and returns
|
||
+#
|
||
+# written by John Bradley for the XV 3.00 release
|
||
+# thanks to John Hagan for shell-script hackery
|
||
+#
|
||
+
|
||
+echo "executing 'ranlib $1'..."
|
||
+
|
||
+# Is there a ranlib? Let's try and then suffer the consequences...
|
||
+ranlib $1 >& /dev/null
|
||
+
|
||
+if [ $? -ne 0 ]; then
|
||
+ echo "There doesn't seem to be a ranlib on this system..."
|
||
+ echo "Don't worry about it."
|
||
+fi
|
||
+
|
||
+echo ""
|
||
+echo ""
|
||
+
|
||
diff -u -r --new-file xv-3.10a.orig/xv_mgcsfx.sample xv-3.10a/xv_mgcsfx.sample
|
||
--- xv-3.10a.orig/xv_mgcsfx.sample 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xv_mgcsfx.sample 2005-04-17 16:04:22.000000000 -0500
|
||
@@ -0,0 +1,125 @@
|
||
+#/*
|
||
+# Configuration file for XV with recognition of 'Magic and Suffix'
|
||
+#
|
||
+#
|
||
+# $Id: xv_mgcsfx.sample,v 1.11 95/10/03 17:00:05 tin329 Exp Locker: tin329 $
|
||
+#
|
||
+# Author: Tetsuya INOUE <tin329@chino.it.okayama-u.ac.jp>
|
||
+#
|
||
+#
|
||
+# MgcSfx definition should write in one line.
|
||
+# Format:
|
||
+# <desc>:<ms type>:<ofs>:<magic>:<suffix>:<in it>:<in c>:<out it>:<out c>
|
||
+# If you decide to not use preprocessor, comment style is allowed.
|
||
+# # <comment>
|
||
+#
|
||
+# <desc> Description of your recognized image format.
|
||
+# <ms type> Type ID for recognition. (You should use 'magic'.)
|
||
+# * magic Data of string style.
|
||
+# `\' escape for special characters:
|
||
+# \b \f \n \r \t \v \\ \' \" \a \?
|
||
+# \0 ...\377 octal value
|
||
+# \x0 ...\xff hexadecimal value
|
||
+# * suffix Suffix of file name.
|
||
+# This type check <suffix> instead
|
||
+# of <magic>.
|
||
+# * [b|l]eint16 2 byte integer of [big|little] endian.
|
||
+# * [b|l]eint32 4 byte integer of [big|little] endian.
|
||
+# <ofs> Offset of magic number in the target image file.
|
||
+# <magic> Data(magic number) of <ms type> to match at <ofs>.
|
||
+# <suffix> Suffix of filename with '.'start.
|
||
+#
|
||
+# <in it> Input image format type (output from <in c>).
|
||
+# * PNM (PPM, PGM, PBM)
|
||
+# * AUTO Recognized by xv management, and load.
|
||
+# This is different from others, because
|
||
+# this write file to temporary.
|
||
+# <out it> Output image format type (input to <out c>).
|
||
+# * PNM_RAW (PPM_RAW, PGM_RAW, PBM_RAW)
|
||
+# * PNM_ASCII (PPM_ASCII, PGM_ASCII, PBM_ASCII)
|
||
+#
|
||
+# <in c> Command to get the input image.
|
||
+# * Command mast read stdin or file(specified by
|
||
+# argument), and write to stdout.
|
||
+# * Use %s to represent the file name. Without %s,
|
||
+# get file on stdin.
|
||
+# <out c> Command to put the output image.
|
||
+# * Command mast read stdin and write to stdout.
|
||
+#
|
||
+# <comment> Any message.
|
||
+#*/
|
||
+
|
||
+#/*############################################################################
|
||
+#
|
||
+# definition of the rule with Magic and Suffix
|
||
+#
|
||
+#*/
|
||
+
|
||
+# /* Canon View Station Image Format */
|
||
+ViewStation(std):magic:0:VsStdImf V0.2:.vs:PNM:VStopnm %s:PNM_RAW:pnmtoVS
|
||
+ViewStation(obj):magic:0:VsObjFormat V1.0:.vs:PNM:VSobjtopnm -:PNM_RAW:pnmtoVSobj
|
||
+
|
||
+# /* CERN httpd cache */
|
||
+# /* unchc skip header of CERN httpd cache file, and write data to stdout. */
|
||
+CERN httpd cache:magic:0:HTTP/1.0::AUTO:unchc %s::
|
||
+
|
||
+# /* XLD4(Q4) image format */
|
||
+XLD(Q4):magic:11:MAJYO:.q4:PNM:q4toppm::
|
||
+
|
||
+# /* ML1 image format */
|
||
+ML1:magic:0:\1\0\0\x1a:.ml1:PNM:ml1toppm %s::
|
||
+
|
||
+# /* Pict image format, 256 color only */
|
||
+PICT:suffix:::.pict:PNM:picttoppm:PNM_RAW:ppmquant 256 | ppmtopict
|
||
+PICT(gzip):suffix:::.pict.gz:PNM:gzip -dc | picttoppm:PNM_RAW:ppmquant 256 | ppmtopict | gzip
|
||
+PICT(compress):suffix:::.pict.Z:PNM:compress -dc | picttoppm:PNM_RAW:ppmquant 256 | ppmtopict | compress
|
||
+
|
||
+# /* Tim image format(used by SONY PlayStation) */
|
||
+TIM:magic:0:\x10\x00\x00\x00:.tim:PNM:timtoppm::
|
||
+
|
||
+# /* Cam image format(used by CASIO QV-10) */
|
||
+# /* CAM:magic:0:\x07\x20\x4d\x4d:.cam:AUTO:camtoppm -j:PNM_RAW */
|
||
+CAM:magic:0:\x07\x20\x4d\x4d:.cam:PNM:camtoppm::
|
||
+
|
||
+# /* Portable Network Graphics (PNG) format : magic is "0x89 PNG" */
|
||
+PNG:magic:0:\x89\x50\x4e\x47:.png:PNM:pngtopnm %s:PNM_RAW:pnmtopng
|
||
+# /* PNG(interlace):magic:0:\x89\x50\x4e\x47:.png:PNM:pngtopnm %s:PNM_RAW:pnmtopng -interlace */
|
||
+
|
||
+# /* DB-Z, SAURUS Freehand Memo, PV-F1 Action Board, Wiz Quick Memo format */
|
||
+# /* Use xbm2free-1.10 or later. Old version is NOT a filter. */
|
||
+# /* To show version of xbm2free, type "xbm2free" (with no argument). */
|
||
+ZAURUS:magic:19:IMG1:.zau:PBM_ASCII:free2pbm:PBM:pbmtoxbm|xbm2free -s -
|
||
+DBZ:magic:19:IMG1:.dbz:::PBM:pbmtoxbm|xbm2free -d -
|
||
+PVF1:magic:12:IMG1:.pvf1:PBM_ASCII:free2pbm:PBM:pbmtoxbm|xbm2free -v -
|
||
+# /* WIZ:magic:19:IMG1:.wiz:::PBM:pbmtoxbm|xbm2free -w - */
|
||
+
|
||
+
|
||
+
|
||
+# /* Compress:magic:0:\037\235:.Z:AUTO:uncompress %s:: */
|
||
+# /* Gzip:magic:0:\037\213:.gz:AUTO:gunzip %s:: */
|
||
+# /* Gzip(old):magic:0:\037\236:.z:AUTO:gunzip %s:: */
|
||
+
|
||
+# /* MAKI:magic:0:MAKI01A\040:.mki:::: */
|
||
+# /* MAKI:magic:0:MAKI01B\040:.mki:::: */
|
||
+# /* MAG:magic:0:MAKI02\040\040:.mag:::: */
|
||
+# /* Pi:magic:0:Pi:.pi:::: */
|
||
+# /* PIC:magic:0:PIC:.pic:::: */
|
||
+# /* PIC2:magic:0:P2DT:.p2:::: */
|
||
+# /* PhotoCD:magic:0:\xff\xff\xff\xff:.pcd:::: */
|
||
+
|
||
+# /* PBM(ascii):magic:0:P1:.pbm:::: */
|
||
+# /* PGM(ascii):magic:0:P2:.pgm:::: */
|
||
+# /* PPM(ascii):magic:0:P3:.ppm:::: */
|
||
+# /* PBM(raw):magic:0:P4:.pbm:::: */
|
||
+# /* PGM(raw):magic:0:P5:.pgm:::: */
|
||
+# /* PPM(raw):magic:0:P6:.ppm:::: */
|
||
+
|
||
+# /* Sun raster:magic:0:\131\246\152\225:.sun:::: */
|
||
+# /* JFIF(JPEG):magic:0:\xff\xd8\xff:.jpg:::: */
|
||
+# /* TIFF big-endian:magic:0:\115\115:.tif:::: */
|
||
+# /* TIFF little-endian:magic:0:\111\111:.tif:::: */
|
||
+# /* GIF(87):magic:0:GIF87a:.gif:::: */
|
||
+# /* GIF(89):magic:0:GIF89a:.gif:::: */
|
||
+# /* SGI(1):magic:0:\x01\xda:.rgb:::: */
|
||
+# /* SGI(2):magic:0:\xda\x01:.rgb:::: */
|
||
+# /* XWD:magic:0:\0\0\0\7: :::: */
|
||
diff -u -r --new-file xv-3.10a.orig/xvhips.c xv-3.10a/xvhips.c
|
||
--- xv-3.10a.orig/xvhips.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvhips.c 2005-05-01 01:49:14.000000000 -0500
|
||
@@ -0,0 +1,406 @@
|
||
+/*
|
||
+ * xvhips.c - load routine for 'HIPS' format pictures
|
||
+ *
|
||
+ * LoadHIPS(fname, numcols)
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * Copyright 1989, 1990 by the University of Pennsylvania
|
||
+ *
|
||
+ * Permission to use, copy, and distribute for non-commercial purposes,
|
||
+ * is hereby granted without fee, providing that the above copyright
|
||
+ * notice appear in all copies and that both the copyright notice and this
|
||
+ * permission notice appear in supporting documentation.
|
||
+ *
|
||
+ * The software may be modified for your own purposes, but modified versions
|
||
+ * may not be distributed.
|
||
+ *
|
||
+ * This software is provided "as is" without any express or implied warranty.
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+
|
||
+#ifdef HAVE_HIPS
|
||
+
|
||
+#define Boolean FREDDIE
|
||
+#include "xvhips.h"
|
||
+#undef Boolean
|
||
+
|
||
+#include <alloca.h>
|
||
+
|
||
+#define LINES 100
|
||
+#define LINELENGTH 132
|
||
+
|
||
+static int fread_header(int fd, struct header *hd);
|
||
+static char *getline(int fd, char **s, int *l);
|
||
+static int dfscanf(int fd);
|
||
+static void make_grayscale(char *r, char *g, char *b);
|
||
+static float hls_value (float n1, float n2, float hue);
|
||
+static void hls_to_rgb(float h, float l, float s,
|
||
+ float *r, float *g, float *b);
|
||
+static void make_huescale(char *r, char *g, char *b);
|
||
+static void make_heatscale(char *r, char *g, char *b);
|
||
+static int load_colourmap(char *filestem, int max_colours,
|
||
+ char *r, char *g, char *b);
|
||
+
|
||
+/************************************************************************
|
||
+ *
|
||
+ * Read Header routines
|
||
+ *
|
||
+ ************************************************************************/
|
||
+
|
||
+static char *ssave[LINES];
|
||
+static int slmax[LINES];
|
||
+static int lalloc = 0;
|
||
+//extern char *calloc();
|
||
+
|
||
+
|
||
+
|
||
+static int fread_header(fd, hd)
|
||
+ int fd;
|
||
+ struct header *hd;
|
||
+{
|
||
+ int lineno, len, i;
|
||
+ char *s;
|
||
+
|
||
+/*fprintf(stderr,"fread_header: entered\n");*/
|
||
+ if(lalloc<1) {
|
||
+ ssave[0] = calloc(LINELENGTH, sizeof (char));
|
||
+ slmax[0] = LINELENGTH;
|
||
+ lalloc = 1;
|
||
+ }
|
||
+/*fprintf(stderr,"fread_header: ssave allocated\n");*/
|
||
+ getline(fd,&ssave[0],&slmax[0]);
|
||
+ hd->orig_name = calloc(strlen(ssave[0])+1, sizeof (char));
|
||
+ strcpy(hd->orig_name,ssave[0]);
|
||
+ getline(fd,&ssave[0],&slmax[0]);
|
||
+ hd->seq_name = calloc(strlen(ssave[0])+1, sizeof (char));
|
||
+ strcpy(hd->seq_name,ssave[0]);
|
||
+ hd->num_frame = dfscanf(fd);
|
||
+ getline(fd,&ssave[0],&slmax[0]);
|
||
+ hd->orig_date = calloc(strlen(ssave[0])+1, sizeof (char));
|
||
+ strcpy(hd->orig_date,ssave[0]);
|
||
+ hd->rows = dfscanf(fd);
|
||
+ hd->cols = dfscanf(fd);
|
||
+ hd->bits_per_pixel = dfscanf(fd);
|
||
+ hd->bit_packing = dfscanf(fd);
|
||
+ hd->pixel_format = dfscanf(fd);
|
||
+ lineno = 0;
|
||
+ len = 1;
|
||
+ getline(fd,&ssave[0],&slmax[0]);
|
||
+ s = ssave[0];
|
||
+ while(*(s += strlen(s)-3) == '|') {
|
||
+ len += strlen(ssave[lineno]);
|
||
+ lineno++;
|
||
+ if (lineno >= LINES)
|
||
+ fprintf(stderr, "Too many lines in header history");
|
||
+ if(lineno >= lalloc) {
|
||
+ ssave[lineno] = calloc(LINELENGTH, sizeof (char));
|
||
+ slmax[lineno] = LINELENGTH;
|
||
+ lalloc++;
|
||
+ }
|
||
+ getline(fd,&ssave[lineno],&slmax[lineno]);
|
||
+ s = ssave[lineno];
|
||
+ }
|
||
+ len += strlen(ssave[lineno]);
|
||
+ hd->seq_history = calloc(len, sizeof (char));
|
||
+ hd->seq_history[0] = '\0';
|
||
+ for (i=0;i<=lineno;i++)
|
||
+ strcat(hd->seq_history,ssave[i]);
|
||
+ lineno = 0;
|
||
+ len = 1;
|
||
+ while(strcmp(getline(fd,&ssave[lineno],&slmax[lineno]),".\n")) {
|
||
+ len += strlen(ssave[lineno]);
|
||
+ lineno++;
|
||
+ if (lineno >= LINES)
|
||
+ fprintf(stderr, "Too many lines in header desc.");
|
||
+ if(lineno >= lalloc) {
|
||
+ ssave[lineno] = calloc(LINELENGTH, sizeof (char));
|
||
+ slmax[lineno] = LINELENGTH;
|
||
+ lalloc++;
|
||
+ }
|
||
+ }
|
||
+ hd->seq_desc = calloc(len, sizeof (char));
|
||
+ *hd->seq_desc = '\0';
|
||
+ for (i=0;i<lineno;i++)
|
||
+ strcat(hd->seq_desc,ssave[i]);
|
||
+/*fprintf(stderr,"fread_header: exiting\n");*/
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static char *getline(fd,s,l)
|
||
+ int fd;
|
||
+ char **s;
|
||
+ int *l;
|
||
+{
|
||
+ int i,m;
|
||
+ char c,*s1,*s2;
|
||
+
|
||
+ i = 0;
|
||
+ s1 = *s;
|
||
+ m = *l;
|
||
+ while(read(fd,&c,1) == 1 && c != '\n') {
|
||
+ if (m-- <= 2) {
|
||
+ s2 = calloc(LINELENGTH+*l,sizeof (char));
|
||
+ strcpy(s2,*s);
|
||
+ *s = s2;
|
||
+ *l += LINELENGTH;
|
||
+ m = LINELENGTH;
|
||
+ s1 = s2 + strlen(s2);
|
||
+ }
|
||
+ *s1++ = c;
|
||
+ }
|
||
+ if (c == '\n') {
|
||
+ *s1++ = '\n';
|
||
+ *s1 = '\0';
|
||
+ return *s;
|
||
+ }
|
||
+ fprintf(stderr, "Unexpected EOF while reading header.");
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static int dfscanf(fd)
|
||
+ int fd;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ getline(fd,&ssave[0],&slmax[0]);
|
||
+ sscanf(ssave[0],"%d",&i);
|
||
+ return(i);
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+int LoadHIPS(fname,pinfo)
|
||
+ char *fname;
|
||
+ PICINFO * pinfo;
|
||
+/*******************************************/
|
||
+{
|
||
+ FILE *fp;
|
||
+ struct header h;
|
||
+ char * pic;
|
||
+
|
||
+ /* open the stream, if necesary */
|
||
+ fp=fopen(fname,"r");
|
||
+ if (!fp) return 0;
|
||
+
|
||
+ if (!fread_header(fileno(fp), &h)) {
|
||
+ SetISTR(ISTR_WARNING,"Can't read HIPS header");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ pinfo->w = h.cols;
|
||
+ pinfo->h = h.rows;
|
||
+ pic = pinfo->pic = (byte *) malloc(h.rows * h.cols); // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ if (!pic) FatalError("couldn't malloc HIPS file");
|
||
+
|
||
+ if (!fread(pic, 1, h.cols*h.rows, fp)) {
|
||
+ SetISTR(ISTR_WARNING,"Error reading HIPS data.\n");
|
||
+ return 0;
|
||
+ }
|
||
+ fclose (fp);
|
||
+
|
||
+ pinfo->frmType = F_SUNRAS;
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ sprintf(pinfo->fullInfo, "HIPS file (%d bytes)", h.cols*h.rows);
|
||
+ sprintf(pinfo->shrtInfo, "HIPS file.");
|
||
+ pinfo->comment = (char *) NULL;
|
||
+
|
||
+ {
|
||
+ char cmapname[256];
|
||
+ /* Check header for colormap spec */
|
||
+ char * s = h.seq_desc - 1;
|
||
+ char * cmaptag = "+COLORMAP";
|
||
+ int sl = strlen(cmaptag);
|
||
+ cmapname[0] = 0;
|
||
+ while (*++s)
|
||
+ if (*s == '+')
|
||
+ if (strncmp(s, cmaptag, sl) == 0) {
|
||
+ char * p = s + sl;
|
||
+ while (*p && (*p == ' ' || *p == '\n' || *p == '\t')) p++;
|
||
+ sscanf(p, "%s", cmapname);
|
||
+ SetISTR(ISTR_INFO, cmapname);
|
||
+ fprintf(stderr, "Colormap = [%s]\n", cmapname);
|
||
+ }
|
||
+
|
||
+ if (strcmp(cmapname, "gray") == 0 || strcmp(cmapname, "grey") == 0)
|
||
+ make_grayscale(pinfo->r, pinfo->g, pinfo->b);
|
||
+ else if (strcmp(cmapname, "heat") == 0)
|
||
+ make_heatscale(pinfo->r, pinfo->g, pinfo->b);
|
||
+ else if (strcmp(cmapname, "hues") == 0)
|
||
+ make_huescale(pinfo->r, pinfo->g, pinfo->b);
|
||
+ else if (!cmapname[0] || !load_colourmap(cmapname, 256, pinfo->r, pinfo->g, pinfo->b))
|
||
+ make_grayscale(pinfo->r, pinfo->g, pinfo->b);
|
||
+ sprintf(pinfo->fullInfo, "HIPS file (%d x %d), Colormap = [%s]", h.cols, h.rows, cmapname);
|
||
+ }
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static void make_grayscale(char * r, char * g, char * b)
|
||
+{
|
||
+ int i;
|
||
+ /* default grayscale colors */
|
||
+ r[0] = 40; g[0] = 150; b[0] = 100; /* "green4" background */
|
||
+ for(i = 1; i < 256; i++)
|
||
+ r[i] = g[i] = b[i] = i;
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static float hls_value (n1, n2, hue)
|
||
+ float n1,n2,hue;
|
||
+{
|
||
+ if (hue>360.0)
|
||
+ hue-=360.0 ;
|
||
+ else if (hue<0.0)
|
||
+ hue+=360.0 ;
|
||
+
|
||
+ if (hue<60.0)
|
||
+ return( n1+(n2-n1)*hue/60.0 ) ;
|
||
+ else if (hue<180.0)
|
||
+ return ( n2 ) ;
|
||
+ else if (hue<240.0)
|
||
+ return ( n1+(n2-n1)*(240.0-hue)/60.0 ) ;
|
||
+ else
|
||
+ return (n1) ;
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static void hls_to_rgb(h,l,s, r,g,b)
|
||
+ float h, l, s;
|
||
+ float *r, *g, *b;
|
||
+{
|
||
+ static float m1, m2 ;
|
||
+
|
||
+ if (l<=0.5)
|
||
+ m2=l*(1+s) ;
|
||
+ else
|
||
+ m2=l+s-l*s ;
|
||
+ m1=2.0*l-m2 ;
|
||
+ if (s==0.0) *r=*g=*b=l ;
|
||
+ else {
|
||
+ *r=hls_value(m1,m2,h+120.0) ;
|
||
+ *g=hls_value(m1,m2,h) ;
|
||
+ *b=hls_value(m1,m2,h-120.0) ;
|
||
+ }
|
||
+
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static void make_huescale(char * r, char * g, char * b)
|
||
+{
|
||
+ int j;
|
||
+ r[0] = g[0] = b[0] = 0;
|
||
+ for (j = 1; j<256; j++)
|
||
+ {
|
||
+ float fr, fg, fb;
|
||
+ hls_to_rgb((double)(256.0-j)*360.0/256.0, 0.5, 1.0, &fr, &fg, &fb);
|
||
+ r[j] = rint(255*fr);
|
||
+ g[j] = rint(255*fg);
|
||
+ b[j] = rint(255*fb);
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static void make_heatscale(char * r, char * g, char * b)
|
||
+{
|
||
+ int j;
|
||
+ r[0] = g[0] = b[0] = 0;
|
||
+ for (j = 1; j<256; j++)
|
||
+ {
|
||
+ if(j<255/2)
|
||
+ r[j] = j*255/(255/2-1);
|
||
+ else
|
||
+ r[j]=255;
|
||
+ if (j>=255/2+255/3)
|
||
+ g[j] = 255;
|
||
+ else if (j>255/3)
|
||
+ g[j] = (j-255/3)*255/(255/2-1);
|
||
+ else
|
||
+ g[j] = 0;
|
||
+ if (j>255/2)
|
||
+ b[j] = (j-255/2)*255/(255-255/2-1);
|
||
+ else
|
||
+ b[j] = 0;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static int load_colourmap(char *filestem, int max_colours,
|
||
+ char *r, char *g, char *b)
|
||
+{
|
||
+ FILE * fp;
|
||
+ int numread=0;
|
||
+ char * filename;
|
||
+ char str[200];
|
||
+ int num_colors;
|
||
+ /*
|
||
+ * Look for palette file in local directory
|
||
+ */
|
||
+
|
||
+ filename = (char*)alloca(strlen(filestem) + 5);
|
||
+ strcpy(filename, filestem);
|
||
+ strcat(filename, ".PAL"); /* Add the PAL suffix to the name specified */
|
||
+ fp = fopen(filename,"r");
|
||
+ if (!fp) {
|
||
+ /*
|
||
+ * If not found, try in $IM2HOME/etc/palettes
|
||
+ */
|
||
+ char * im2home = (char*)getenv("IM2HOME");
|
||
+ char * palette_subdirectory = "etc/palettes";
|
||
+ char * fullfilename;
|
||
+ if (!im2home)
|
||
+ {
|
||
+ im2home = "/home/jewel/imagine2";
|
||
+ fprintf(stderr,"IM2HOME environment variable not set -- using [%s]\n",im2home);
|
||
+ }
|
||
+ fullfilename = alloca(strlen(im2home)+strlen(palette_subdirectory)+strlen(filename)+5);
|
||
+ sprintf(fullfilename, "%s/%s/%s",im2home,palette_subdirectory,filename);
|
||
+ fp = fopen(fullfilename,"r");
|
||
+ if (!fp)
|
||
+ {
|
||
+ fprintf(stderr,"Couldn't find any palette file -- looked for [%s] and [%s].\n",
|
||
+ filename,fullfilename);
|
||
+ perror("Last system error message was");
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ strcpy(str,"(null)");
|
||
+ if (!fscanf(fp,"%s\n",str) || strncmp(str,"Palette",7) != 0) {
|
||
+ fprintf(stderr,"error: First line of palette file should be `Palette', not [%s]\n", str);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ fscanf(fp,"%[^\n]",str) ; /* Scan to end of line */
|
||
+ fscanf (fp,"%d",&num_colors);/* Read the number of colours in the file */
|
||
+ fgets(str,120,fp) ; /* Skip the text description, and general info lines */
|
||
+ fgets(str,120,fp) ;
|
||
+
|
||
+ while ((numread<max_colours)&&(numread<num_colors)) {
|
||
+ int rc, gc, bc;
|
||
+ fscanf (fp,"%d %d %d -", &rc, &gc, &bc) ; /* Get the (r,g,b) tuples */
|
||
+ r[numread] = rc;
|
||
+ g[numread] = gc;
|
||
+ b[numread] = bc;
|
||
+ numread++;
|
||
+ fgets(str,120,fp) ; /* Skip the description, if present */
|
||
+ }
|
||
+
|
||
+ SetISTR(ISTR_INFO,"Read %d colors from palette file [%s]", numread, filename);
|
||
+ return (numread) ; /* Return the number of colours ACTUALLY READ */
|
||
+}
|
||
+
|
||
+#endif /* HAVE_HIPS */
|
||
diff -u -r --new-file xv-3.10a.orig/xvhips.h xv-3.10a/xvhips.h
|
||
--- xv-3.10a.orig/xvhips.h 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvhips.h 2005-04-25 10:34:14.000000000 -0500
|
||
@@ -0,0 +1,154 @@
|
||
+/*
|
||
+ * HIPL Picture Header Format Standard
|
||
+ *
|
||
+ * Michael Landy - 2/1/82
|
||
+ */
|
||
+
|
||
+#define XHEADER
|
||
+#ifdef XHEADER
|
||
+struct extended {
|
||
+ char *name;
|
||
+ char *vals;
|
||
+ };
|
||
+#endif
|
||
+
|
||
+struct header {
|
||
+ char *orig_name; /* The originator of this sequence */
|
||
+ char *seq_name; /* The name of this sequence */
|
||
+ int num_frame; /* The number of frames in this sequence */
|
||
+ char *orig_date; /* The date the sequence was originated */
|
||
+ int rows; /* The number of rows in each image */
|
||
+ int cols; /* The number of columns in each image */
|
||
+ int bits_per_pixel; /* The number of significant bits per pixel */
|
||
+ int bit_packing; /* Nonzero if bits were packed contiguously */
|
||
+ int pixel_format; /* The format of each pixel, see below */
|
||
+ char *seq_history; /* The sequence's history of transformations */
|
||
+ char *seq_desc; /* Descriptive information */
|
||
+#ifdef XHEADER
|
||
+ struct extended *xheader;
|
||
+#endif
|
||
+};
|
||
+
|
||
+/*
|
||
+ * Pixel Format Codes
|
||
+ */
|
||
+
|
||
+#define PFBYTE 0 /* Bytes interpreted as integers (8 bits) */
|
||
+#define PFSHORT 1 /* Short integers (2 bytes) */
|
||
+#define PFINT 2 /* Integers (4 bytes) */
|
||
+#define PFFLOAT 3 /* Float's (4 bytes)*/
|
||
+#define PFCOMPLEX 4 /* 2 Float's interpreted as (real,imaginary) */
|
||
+#define PFASCII 5 /* ASCII rep, with linefeeds after each row */
|
||
+#define PFDOUBLE 6 /* Double's (8 byte floats) */
|
||
+#define PFDBLCOM 7 /* Double complex's (2 Double's) */
|
||
+#define PFQUAD 10 /* quad-tree encoding (Mimaging) */
|
||
+#define PFQUAD1 11 /* quad-tree encoding */
|
||
+#define PFBHIST 12 /* histogram of byte image (using ints) */
|
||
+#define PFSPAN 13 /* spanning tree format */
|
||
+#define PLOT3D 24 /* plot-3d format */
|
||
+#define PFINTPYR 50 /* integer pyramid */
|
||
+#define PFFLOATPYR 51 /* float pyramid */
|
||
+#define PFPOLYLINE 100 /* 2D points */
|
||
+#define PFCOLVEC 101 /* Set of RGB triplets defining colours */
|
||
+#define PFUKOOA 102 /* Data in standard UKOOA format */
|
||
+#define PFTRAINING 104 /* Set of colour vector training examples */
|
||
+#define PFTOSPACE 105 /* TOspace world model data structure */
|
||
+#define PFSTEREO 106 /* Stereo sequence (l, r, l, r, ...) */
|
||
+#define PFRGPLINE 107 /* 2D points with regions */
|
||
+#define PFRGISPLINE 108 /* 2D points with regions and interfaces */
|
||
+#define PFCHAIN 200 /* Chain code encoding (Mimaging) */
|
||
+#define PFLUT 300 /* LUT format (uses Ints) (Mimaging) */
|
||
+#define PFAHC 400 /* adaptive hierarchical encoding */
|
||
+#define PFOCT 401 /* oct-tree encoding */
|
||
+#define PFBT 402 /* binary tree encoding */
|
||
+#define PFAHC3 403 /* 3-d adaptive hierarchical encoding */
|
||
+#define PFBQ 404 /* binquad encoding */
|
||
+#define PFRLED 500 /* run-length encoding */
|
||
+#define PFRLEB 501 /* run-length encoding, line begins black */
|
||
+#define PFRLEW 502 /* run-length encoding, line begins white */
|
||
+#define PFPOLAR 600 /* rho-theta format (Mimaging) */
|
||
+
|
||
+/*
|
||
+ * Bit packing formats
|
||
+ */
|
||
+
|
||
+#define MSBFIRST 1 /* bit packing - most significant bit first */
|
||
+#define LSBFIRST 2 /* bit packing - least significant bit first */
|
||
+
|
||
+#define FBUFLIMIT 30000 /* increase this if you use large PLOT3D
|
||
+ files */
|
||
+
|
||
+/*
|
||
+ * For general readability
|
||
+ */
|
||
+
|
||
+#ifndef TRUE
|
||
+# define TRUE 1
|
||
+#endif
|
||
+
|
||
+#ifndef FALSE
|
||
+# define FALSE 0
|
||
+#endif
|
||
+
|
||
+typedef long Boolean;
|
||
+extern char *strsave(), *memalloc();
|
||
+
|
||
+/*
|
||
+ * image and pyramid type declarations for the pyramid routines.
|
||
+ *
|
||
+ * The pyramid utilities are derived from code originally written by
|
||
+ * Raj Hingorani at SRI/David Sarnoff Research Institute. The original
|
||
+ * Gaussian and Laplacian pyramid algorithms were designed by Peter Burt (also
|
||
+ * currently at SRI/DSRC). See: Computer Graphics and Image Processing,
|
||
+ * Volume 16, pp. 20-51, 1981, and IEEE Transactions on Communications,
|
||
+ * Volume COM-31, pp. 532-540, 1983.
|
||
+ */
|
||
+
|
||
+#define MAXLEV 12
|
||
+
|
||
+
|
||
+typedef struct {
|
||
+ float **ptr;
|
||
+ int nr;
|
||
+ int nc;
|
||
+} FIMAGE;
|
||
+
|
||
+typedef struct {
|
||
+ int **ptr;
|
||
+ int nr;
|
||
+ int nc;
|
||
+} IIMAGE;
|
||
+
|
||
+typedef FIMAGE FPYR[MAXLEV];
|
||
+typedef IIMAGE IPYR[MAXLEV];
|
||
+
|
||
+typedef struct {
|
||
+ float *k;
|
||
+ int taps2; /* the number of taps from the center rightward,
|
||
+ total number is 2*taps2-1 */
|
||
+} FILTER;
|
||
+
|
||
+/* function definitions */
|
||
+
|
||
+float **_read_fimgstr();
|
||
+int **_read_iimgstr();
|
||
+float **_alloc_fimage();
|
||
+int **_alloc_iimage();
|
||
+
|
||
+/* image macros */
|
||
+
|
||
+#ifndef MAX
|
||
+# define MAX(A,B) ((A) > (B) ? (A) : (B))
|
||
+#endif /* MAX */
|
||
+#ifndef MIN
|
||
+# define MIN(A,B) ((A) < (B) ? (A) : (B))
|
||
+#endif /* MIN */
|
||
+#ifndef ABS
|
||
+# define ABS(A) ((A) > 0 ? (A) : (-(A)))
|
||
+#endif /* ABS */
|
||
+#ifndef BETWEEN
|
||
+# define BETWEEN(A,B,C) (((A) < (B)) ? (B) : (((A) > (C)) ? (C) : (A)))
|
||
+#endif /* BETWEEN */
|
||
+#ifndef SIGN
|
||
+# define SIGN(A,B) (((B) > 0) ? (A) : (-(A)))
|
||
+#endif /* SIGN */
|
||
diff -u -r --new-file xv-3.10a.orig/xvjp2k.c xv-3.10a/xvjp2k.c
|
||
--- xv-3.10a.orig/xvjp2k.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvjp2k.c 2007-05-13 20:04:37.000000000 -0500
|
||
@@ -0,0 +1,1326 @@
|
||
+/*
|
||
+ * xvjp2k.c - I/O subroutines for JPEG 2000 format pictures
|
||
+ *
|
||
+ * This module is a "shim" between XV and a JPEG 2000 CODEC in the open-source
|
||
+ * JasPer Library created by Michael D. Adams; for more information, see the URL
|
||
+ * "http://www.ece.uvic.ca/~mdadams/jasper". We don't use most of the other
|
||
+ * facilities in this library, so it's better to link XV with a UNIX "archive"
|
||
+ * representation of it, not a DLL.
|
||
+ *
|
||
+ * JPEG 2000 files can be represented in either of two general ways: The
|
||
+ * simplest representation is a "code stream", which often has a ".jpc" file
|
||
+ * name suffix and is organized much like a classical JPEG file, except that
|
||
+ * unfortunately, JPEG 2000 code streams indicate the no. of colors in an image
|
||
+ * but no longer give any clues about its color space (e.g., RGB or YCbCr).
|
||
+ * Instead, there is now a semantically higher-level representation, which often
|
||
+ * has a ".jp2" file name suffix and encapsulates a "code stream" with (possibly
|
||
+ * a lot of) color-space information, optionally including things like ICC
|
||
+ * correction tables.
|
||
+ *
|
||
+ * Compared to the IJG JPEG Library used in file "xvjpeg.c", one must solve
|
||
+ * several problems for color images when marrying JasPer to XV.
|
||
+ *
|
||
+ * 1. JPEG 2000 files can represent a wide range of image sizes, resolutions,
|
||
+ * and color spaces, not all of which can be easily rendered "as is" on a
|
||
+ * normal "X Windows" display, so we must carefully check a decoded image's
|
||
+ * parameters in order to reject anything that we can't handle gracefully.
|
||
+ *
|
||
+ * 2. JasPer prefers to decode/encode images using color-plane "slices", instead
|
||
+ * of interleaved pixels needed by "X Windows", so we must (de)interleave
|
||
+ * copies of the image buffer here.
|
||
+ *
|
||
+ * XXX Things to do:
|
||
+ *
|
||
+ * 1. In "LoadJP{2,C}()" try to handle the "quick" option, which requests
|
||
+ * faster loading of a reduced-size image for the visual schnauzer. The
|
||
+ * schnauzer's icon size is currently 80x60, so the old "xvjpeg.c" module tries
|
||
+ * to produce a 2X (160x120) image. Can we do the same?
|
||
+ *
|
||
+ * 2. In "StoreJP2K()", JasPer Library Version 1.701 apparently has no API to
|
||
+ * let the XV global "picComments" string be inserted in a JPEG 2000 comment
|
||
+ * record. If the library ever gets fixed, enhance our code accordingly.
|
||
+ *
|
||
+ * --Scott Marovich <marovich@hpl.hp.com>, Hewlett-Packard Laboratories,
|
||
+ * January 2005.
|
||
+ */
|
||
+#include "copyright.h"
|
||
+
|
||
+#define NEEDSARGS
|
||
+#include "xv.h"
|
||
+
|
||
+#ifdef HAVE_JP2K
|
||
+
|
||
+#include <jasper/jasper.h>
|
||
+/* missing prototype in 1.701.0, sigh: */
|
||
+jas_stream_t *jas_stream_freopen PARM((const char *, const char *, FILE *));
|
||
+
|
||
+static const char *fbasename, /* File's base name, for error/warning msgs */
|
||
+ bad_samp[] = "%s: can't read %d-plane %s file!",
|
||
+ fmode[] = "rb",
|
||
+ full_msg[] = "%s %s. (%ld bytes)",
|
||
+ jp2_kind[] = "JP2",
|
||
+ jpc_kind[] = "JPEG 2000",
|
||
+ load_msg[] = "Loading %dx%d %s %s (%ld bytes)...",
|
||
+ no_mem[] = "%s: can't read %s file - out of memory",
|
||
+ pixel_size[] = "%s: can't display %d-bit pixels!",
|
||
+ shrt_msg[] = "%dx%d %s %s. ",
|
||
+ truncated[] = "%s: Unexpected end of %s file",
|
||
+ read_err[] = "%s: I/O error reading %s file",
|
||
+ bad_dims[] = "%s: error in JPEG-2000 header (bad image size)";
|
||
+
|
||
+/* We only want to override the JasPer Library's "jas_eprintf()" subroutine in
|
||
+ order to make it a "wrapper" around XV's own error-reporting subroutine, but
|
||
+ because of the way the former is currently packaged in JasPer Library Version
|
||
+ 1.701, we must override everything else packaged in the "jas_debug.o" module
|
||
+ with it, otherwise we get "duplicate definition" messages from the linker.
|
||
+*/
|
||
+int jas_getdbglevel(void) {return 0;}
|
||
+int jas_setdbglevel(int n) {return 0;}
|
||
+int jas_memdump(FILE *fp,void *data,size_t len) {return 0;}
|
||
+
|
||
+int jas_eprintf(const char *fmt,...) /* Handle JasPer Library message */
|
||
+{
|
||
+ static char error[] = "error: ", warning[]= "warning: ";
|
||
+ va_list ap;
|
||
+ int kind = ISTR_WARNING;
|
||
+ char buffer[512];
|
||
+ register char *p;
|
||
+
|
||
+ /* Unlike the IJG JPEG Library, the JasPer Library current has no graceful way
|
||
+ for an application (= us!) to intercept its diagnostic messages and output
|
||
+ them using our own subroutines, so this ugly replacement for its output
|
||
+ subroutine will have to suffice. At Version 1.701, lthough the library's
|
||
+ own "jas_eprintf()" is a varargs subroutine, all calls currently pass just
|
||
+ 1 string with a Line Feed at the end and no "printf(3C)" arguments. Most
|
||
+ strings begin with "error: " or "warning: ", although a few have neither.
|
||
+ We try to translate these into the format preferred by XV, trimming any
|
||
+ trailing Line Feed character (ugh!).
|
||
+ */
|
||
+ va_start(ap, fmt);
|
||
+ vsnprintf(p = buffer,512,fmt,ap);
|
||
+ va_end(ap);
|
||
+ while (*p++);
|
||
+ if (p[-2] == '\n') p[-2] = '\0';
|
||
+ p = buffer;
|
||
+ if (strncmp(p,error,sizeof error) == 0) /* "error: ... " */
|
||
+ {
|
||
+ kind = ISTR_WARNING;
|
||
+ p += sizeof error;
|
||
+ }
|
||
+ else /* "warning: ... " */
|
||
+ if (strncmp(p,warning,sizeof warning) == 0)
|
||
+ {
|
||
+ kind = ISTR_INFO;
|
||
+ p += sizeof warning;
|
||
+ };
|
||
+ SetISTR(kind,"%s: %s",fbasename,p);
|
||
+ return strlen(fmt);
|
||
+}
|
||
+
|
||
+static char *SetBuf(FILE *f)
|
||
+{
|
||
+ char *buf;
|
||
+ register char *p;
|
||
+
|
||
+ /* JPEG 2000 image files are apt to be large, but the buffer size allocated by
|
||
+ most implementations of the "C" Standard I/O Library is still ridiculously
|
||
+ small, typically 1 KB. We want to allocate a much larger buffer for higher
|
||
+ I/O efficiency, but the details are unfortunately a bit platform-specific.
|
||
+ Under UNIX systems with virtual memory, we want to encourage its internal
|
||
+ "physio()" subroutine by making the buffer an integral number of pages,
|
||
+ aligned on a page-multiple memory address boundary. Under HP-UX 11.1+ and
|
||
+ perhaps other operating-systems, a Standard I/O buffer is preceded by a
|
||
+ header whose size must also be taken into account.
|
||
+ */
|
||
+# ifndef IOBUFSIZ
|
||
+# define IOBUFSIZ 65536
|
||
+# endif /* IOBUFSIZ */
|
||
+# ifdef __hpux
|
||
+# define OVERHEAD sizeof(mbstate_t)
|
||
+# endif /* __hpux */
|
||
+# ifndef OVERHEAD
|
||
+# define OVERHEAD 0
|
||
+# endif /* OVERHEAD */
|
||
+
|
||
+# ifdef NBPG
|
||
+ if (!(buf = p = malloc(NBPG+OVERHEAD+IOBUFSIZ))) return 0;
|
||
+ p = (char *)((unsigned long)p+NBPG-1 & ~(NBPG-1));
|
||
+ p -= OVERHEAD;
|
||
+# else /* not NBPG */
|
||
+ if (!(buf = p = malloc(OVERHEAD+IOBUFSIZ))) return 0;
|
||
+ p += OVERHEAD;
|
||
+# endif /* NBPG */
|
||
+ setvbuf(f,p,_IOFBF,OVERHEAD+IOBUFSIZ);
|
||
+ return buf;
|
||
+# undef OVERHEAD
|
||
+# undef IOBUFSIZ
|
||
+}
|
||
+
|
||
+int LoadJPC(char *fname,register PICINFO *pinfo,int quick)
|
||
+{
|
||
+ jas_image_t *img;
|
||
+ jas_stream_t *str;
|
||
+ FILE *fp;
|
||
+ char *iobuf;
|
||
+ const char *s;
|
||
+ unsigned long filesize;
|
||
+ long w, h, npixels, bufsize;
|
||
+ int ok = 0, vstride;
|
||
+ register int i;
|
||
+
|
||
+ /* Load a JPEG 2000 "code stream" image file into a pixel buffer for XV.
|
||
+ Unlike classical JPEG files, they have no clue about the image's color
|
||
+ space, so we check for 8-bit data samples but make no effort to check or
|
||
+ convert color spaces, and "what you see is what you get". For now, ignore
|
||
+ the "quick" option to return a reduced-resolution or -size image. Return 1
|
||
+ on success, or 0 on failure.
|
||
+ */
|
||
+ if (!(fp = xv_fopen(fname,fmode))) return 0;
|
||
+ fbasename = BaseName(fname); /* Input file's base name, for message(s) */
|
||
+ if (!(iobuf = SetBuf(fp)))
|
||
+ {
|
||
+ (void)fclose(fp);
|
||
+ SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind);
|
||
+ goto L3;
|
||
+ }
|
||
+
|
||
+ /* Before telling the JasPer Library about this file, get its size for display
|
||
+ purposes. Non-UNIX systems don't necessarily simulate "stat(2)", so do it
|
||
+ crudely but portably by seeking to the end, then back to the beginning.
|
||
+ */
|
||
+ fseek(fp,0L,2);
|
||
+ filesize = ftell(fp);
|
||
+ fseek(fp,0L,0);
|
||
+
|
||
+ /* "jas_stream_close()" will eventually close the input file, so only do it
|
||
+ explicitly if no stream can be created:
|
||
+ */
|
||
+ if (!(str = jas_stream_freopen(fname,fmode,fp))) /* nice if prototype... */
|
||
+ {
|
||
+ (void)fclose(fp);
|
||
+ goto L3;
|
||
+ }
|
||
+
|
||
+ /* It's not clear to me whether the following represents a JasPer Library "bug"
|
||
+ but it sure looks goofy: Unless a stream buffer is marked "read only",
|
||
+ which only happens when the stream's "fillbuf" method is called, even though
|
||
+ our buffers are always "read only", the library will try to flush out buffer
|
||
+ contents when the stream is destroyed, which makes it die a horrible death.
|
||
+ So, mark the stream buffer proactively:
|
||
+ */
|
||
+ str->bufmode_ |= JAS_STREAM_RDBUF; /* We will only read the stream buffer */
|
||
+ if (!(img = jpc_decode(str,0))) goto L2;
|
||
+ if ((vstride = jas_image_numcmpts(img))) /* num. color planes */
|
||
+ {
|
||
+
|
||
+ /* After the image-component streams created, they are left in a "write"
|
||
+ state with the streams' cursors positioned at their ends, so "seek" in
|
||
+ order to "read" each stream from its beginning.
|
||
+ */
|
||
+ i = vstride;
|
||
+ while (--i >= 0)
|
||
+ if (jas_stream_seek(img->cmpts_[i]->stream_,0L,0))
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,read_err,fbasename,jpc_kind);
|
||
+ goto L1;
|
||
+ }
|
||
+ }
|
||
+ w = jas_image_width(img);
|
||
+ h = jas_image_height(img);
|
||
+
|
||
+ /* avoid buffer overflow */
|
||
+ npixels = w * h;
|
||
+ bufsize = vstride * npixels;
|
||
+ if (w <= 0 || h <= 0 || npixels/w != h || bufsize/vstride != npixels)
|
||
+ {
|
||
+ (void)fclose(fp);
|
||
+ SetISTR(ISTR_WARNING,bad_dims,fbasename);
|
||
+ goto L1;
|
||
+ }
|
||
+ pinfo->normw = pinfo->w = w;
|
||
+ pinfo->normh = pinfo->h = h;
|
||
+
|
||
+ /* Sanity-check the image's color space and no. of colors. For now, accept
|
||
+ only "generic" color spaces, not files needing image-specific color
|
||
+ correction, but fix that someday...
|
||
+ */
|
||
+ switch (vstride)
|
||
+ {
|
||
+ default:
|
||
+ SetISTR(ISTR_WARNING,bad_samp,fbasename,vstride,jpc_kind);
|
||
+ goto L1;
|
||
+ case 1:
|
||
+ if ((i = jas_image_cmptprec(img,0)) != 8) /* not 8-bit pixels */
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,pixel_size,fbasename,i);
|
||
+ goto L1;
|
||
+ }
|
||
+ s = "Greyscale";
|
||
+ pinfo->type = PIC8;
|
||
+ pinfo->colType = F_GREYSCALE;
|
||
+ i = 256; /* Return fake indexed-color "map" */
|
||
+ while (--i >= 0) pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
|
||
+ break;
|
||
+ case 3:
|
||
+
|
||
+ /* BEWARE OF KLUDGE: If the image's color space is RGB, assume that the
|
||
+ data-sample precision for all color planes is the
|
||
+ same. If the color space is YCbCr, assume the luminance (Y = 0th)
|
||
+ component has the greatest precision, although the chrominance
|
||
+ (Cr = 1st, Cb = 2nd) components are usually sub-sampled.
|
||
+ */
|
||
+ if ((i = jas_image_cmptprec(img,0)) != 8) /* not 24-bit pixels */
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,pixel_size,fbasename,i*3);
|
||
+ goto L1;
|
||
+ }
|
||
+ s = "Color";
|
||
+ pinfo->type = PIC24;
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+
|
||
+ /* XXX Unlike the IJG JPEG Library, the JasPer Library is apparently
|
||
+ unable to quantize colors or tell us whether the image's colors
|
||
+ were quantized by its creator, so it seems that we can't return a
|
||
+ color map for XV to potentially use 8-bit indexed color. If there
|
||
+ *is* an easy way to do it that escapes me, put the code here someday.
|
||
+ */
|
||
+ }
|
||
+ if (!(pinfo->pic = (byte *)malloc(bufsize))) /* image buffer for XV */
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind);
|
||
+ goto L1;
|
||
+ }
|
||
+ pinfo->frmType = F_JPC;
|
||
+ sprintf(pinfo->fullInfo,full_msg,s,jpc_kind,filesize);
|
||
+ sprintf(pinfo->shrtInfo,shrt_msg,pinfo->w,pinfo->h,s,jpc_kind);
|
||
+ SetISTR(ISTR_INFO,load_msg,pinfo->normw,pinfo->normh,s,jpc_kind,filesize);
|
||
+ if (vstride == 1) /* gray-scale image */
|
||
+ { register jas_stream_t *c = img->cmpts_[0]->stream_;
|
||
+ register byte *p = pinfo->pic;
|
||
+
|
||
+ /* Since this is a 1-plane image, avoid a lot of errant nonsense in the
|
||
+ JasPer Library by sequentially reading all of the data into our buffer
|
||
+ directly.
|
||
+ */
|
||
+ do if ((i = (*c->ops_->read_)(c->obj_,(char *)p,bufsize)) <= 0)
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,i < 0 ? read_err : truncated,fbasename,
|
||
+ jpc_kind);
|
||
+ goto L1;
|
||
+ }
|
||
+ while ((p += i),(bufsize -= i) > 0);
|
||
+ }
|
||
+ else /* RGB color image */
|
||
+ {
|
||
+
|
||
+ /* Reading color images is inefficient because JPEG 2000 wants to partition
|
||
+ file data into separate image planes (colors), while XV wants data
|
||
+ samples from each plane to be interleaved as 3-byte pixels. Apparently
|
||
+ the fastest method consists of 3 passes through the XV image buffer,
|
||
+ into which we insert the bytes of each component.
|
||
+ */
|
||
+ i = 0;
|
||
+ do /* each color component */
|
||
+ { long npix = npixels;
|
||
+ register jas_stream_t *c = img->cmpts_[i]->stream_;
|
||
+ register byte *p = pinfo->pic + i;
|
||
+
|
||
+ do /* each pixel */
|
||
+ { register int b;
|
||
+
|
||
+ if ((b = jas_stream_getc(c)) < 0)
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,
|
||
+ (c->flags_ & JAS_STREAM_EOF) ? truncated : read_err,
|
||
+ fbasename,jpc_kind);
|
||
+ goto L1;
|
||
+ }
|
||
+ *p = b;
|
||
+ }
|
||
+ while ((p += 3),--npix > 0);
|
||
+ }
|
||
+ while (++i <= 2);
|
||
+ }
|
||
+ ok = 1; /* Success! */
|
||
+L1: jas_image_destroy(img);
|
||
+L2: (void)jas_stream_close(str);
|
||
+ free(iobuf);
|
||
+L3: return ok;
|
||
+}
|
||
+
|
||
+int LoadJP2(char *fname,register PICINFO *pinfo,int quick)
|
||
+{
|
||
+ jas_image_t *img;
|
||
+ jas_stream_t *str;
|
||
+ FILE *fp;
|
||
+ char *iobuf;
|
||
+ const char *s;
|
||
+ unsigned long filesize;
|
||
+ long w, h, npixels, bufsize;
|
||
+ int ok = 0, vstride;
|
||
+ register int i;
|
||
+
|
||
+ /* Load a JPEG 2000 JP2 image file into a pixel buffer for XV, doing any
|
||
+ necessary color-space conversion to end up with 8-bit gray scale or 24-bit
|
||
+ RGB. For now, ignore the "quick" option to return a reduced-resolution
|
||
+ or -size image. Return 1 on success, or 0 on failure.
|
||
+ */
|
||
+ if (!(fp = xv_fopen(fname,fmode))) return 0;
|
||
+ fbasename = BaseName(fname); /* Input file's base name, for message(s) */
|
||
+ if (!(iobuf = SetBuf(fp)))
|
||
+ {
|
||
+ (void)fclose(fp);
|
||
+ SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind);
|
||
+ goto L3;
|
||
+ }
|
||
+
|
||
+ /* Before telling the JasPer Library about this file, get its size for display
|
||
+ purposes. Non-UNIX systems don't necessarily simulate "stat(2)", so do it
|
||
+ crudely but portably by seeking to the end, then back to the beginning.
|
||
+ */
|
||
+ fseek(fp,0L,2);
|
||
+ filesize = ftell(fp);
|
||
+ fseek(fp,0L,0);
|
||
+
|
||
+ /* "jas_stream_close()" will eventually close the input file, so only do it
|
||
+ explicitly if no stream can be created:
|
||
+ */
|
||
+ if (!(str = jas_stream_freopen(fname,fmode,fp)))
|
||
+ {
|
||
+ (void)fclose(fp);
|
||
+ goto L3;
|
||
+ }
|
||
+
|
||
+ /* It's not clear to me whether the following represents a JasPer Library "bug"
|
||
+ but it sure looks goofy: Unless a stream buffer is marked "read only",
|
||
+ which only happens when the stream's "fillbuf" method is called, even though
|
||
+ our buffers are always "read only", the library will try to flush out buffer
|
||
+ contents when the stream is destroyed, which makes it die a horrible death.
|
||
+ So, mark the stream buffer proactively:
|
||
+ */
|
||
+ str->bufmode_ |= JAS_STREAM_RDBUF; /* We will only read the stream buffer */
|
||
+ if (!(img = jp2_decode(str,0))) goto L2;
|
||
+ if ((vstride = jas_image_numcmpts(img))) /* num. color planes */
|
||
+ {
|
||
+
|
||
+ /* After the image-component streams created, they are left in a "write"
|
||
+ state with the streams' cursors positioned at their ends, so "seek" in
|
||
+ order to "read" each stream from its beginning.
|
||
+ */
|
||
+ i = vstride;
|
||
+ while (--i >= 0)
|
||
+ if (jas_stream_seek(img->cmpts_[i]->stream_,0L,0))
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,read_err,fbasename,jp2_kind);
|
||
+ goto L1;
|
||
+ }
|
||
+ }
|
||
+ w = jas_image_width(img);
|
||
+ h = jas_image_height(img);
|
||
+
|
||
+ /* avoid buffer overflow */
|
||
+ npixels = w * h;
|
||
+ bufsize = vstride * npixels;
|
||
+ if (w <= 0 || h <= 0 || npixels/w != h || bufsize/vstride != npixels)
|
||
+ {
|
||
+ (void)fclose(fp);
|
||
+ SetISTR(ISTR_WARNING,bad_dims,fbasename);
|
||
+ goto L1;
|
||
+ }
|
||
+ pinfo->normw = pinfo->w = w;
|
||
+ pinfo->normh = pinfo->h = h;
|
||
+
|
||
+ /* Sanity-check the image's color space and no. of colors. For now, accept
|
||
+ only "generic" color spaces, not files needing image-specific color
|
||
+ correction, but fix that someday...
|
||
+ */
|
||
+ switch (vstride)
|
||
+ { static char color_space[]={"%s: invalid color space!"};
|
||
+
|
||
+ default:
|
||
+ SetISTR(ISTR_WARNING,bad_samp,fbasename,vstride,jp2_kind);
|
||
+ goto L1;
|
||
+ case 1:
|
||
+ if ( !jas_clrspc_isunknown(i = jas_image_clrspc(img))
|
||
+ && jas_clrspc_fam(i) != JAS_CLRSPC_FAM_GRAY
|
||
+ )
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,color_space,fbasename);
|
||
+ goto L1;
|
||
+ }
|
||
+ if ((i = jas_image_cmptprec(img,0)) != 8) /* not 8-bit pixels */
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,pixel_size,fbasename,i);
|
||
+ goto L1;
|
||
+ }
|
||
+ s = "Greyscale";
|
||
+ pinfo->type = PIC8;
|
||
+ pinfo->colType = F_GREYSCALE;
|
||
+ i = 256; /* Return fake indexed-color "map" */
|
||
+ while (--i >= 0) pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
|
||
+ break;
|
||
+ case 3:
|
||
+ if (jas_clrspc_isunknown(i = jas_image_clrspc(img)))
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,color_space,fbasename);
|
||
+ goto L1;
|
||
+ }
|
||
+ if (jas_clrspc_fam(i) != JAS_CLRSPC_FAM_RGB)
|
||
+ { jas_image_t *oimg;
|
||
+ jas_cmprof_t *profile;
|
||
+
|
||
+ /* Here's where the JasPer Library really shines. The only color
|
||
+ space that XV handles is RGB, so if that's not what our image
|
||
+ uses, then to quote Capt. Kirk: "Make it so!"
|
||
+ */
|
||
+ if (!(profile = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB)))
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,"%s: can't create RGB profile",
|
||
+ fbasename);
|
||
+ goto L1;
|
||
+ }
|
||
+ img = jas_image_chclrspc( oimg = img
|
||
+ , profile
|
||
+ , JAS_CMXFORM_INTENT_PER
|
||
+ );
|
||
+ jas_cmprof_destroy(profile);
|
||
+ if (!img) /* Oops! We failed, so restore original image */
|
||
+ {
|
||
+ img = oimg;
|
||
+ SetISTR(ISTR_WARNING,"%s: can't convert to RGB",fbasename);
|
||
+ goto L1;
|
||
+ }
|
||
+ jas_image_destroy(oimg);
|
||
+ }
|
||
+
|
||
+ /* BEWARE OF KLUDGE: If the image's color space is RGB, assume that the
|
||
+ data-sample precision for all color planes is the
|
||
+ same. If the color space is YCbCr, assume the luminance (Y = 0th)
|
||
+ component has the greatest precision, although the chrominance
|
||
+ (Cr = 1st, Cb = 2nd) components are usually sub-sampled.
|
||
+ */
|
||
+ if ((i = jas_image_cmptprec(img,0)) != 8) /* not 24-bit pixels */
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,pixel_size,fbasename,i*3);
|
||
+ goto L1;
|
||
+ }
|
||
+ s = "Color";
|
||
+ pinfo->type = PIC24;
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+
|
||
+ /* XXX Unlike the IJG JPEG Library, the JasPer Library is apparently
|
||
+ unable to quantize colors or tell us whether the image's colors
|
||
+ were quantized by its creator, so it seems that we can't return a
|
||
+ color map for XV to potentially use 8-bit indexed color. If there
|
||
+ *is* an easy way to do it that escapes me, put the code here someday.
|
||
+ */
|
||
+ }
|
||
+ if (!(pinfo->pic = (byte *)malloc(bufsize))) /* image buffer for XV */
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,no_mem,fbasename,jp2_kind);
|
||
+ goto L1;
|
||
+ }
|
||
+ pinfo->frmType = F_JP2;
|
||
+ sprintf(pinfo->fullInfo,full_msg,s,jp2_kind,filesize);
|
||
+ sprintf(pinfo->shrtInfo,shrt_msg,pinfo->w,pinfo->h,s,jp2_kind);
|
||
+ SetISTR(ISTR_INFO,load_msg,pinfo->normw,pinfo->normh,s,jp2_kind,filesize);
|
||
+ if (vstride == 1) /* gray-scale image */
|
||
+ { register jas_stream_t *c = img->cmpts_[0]->stream_;
|
||
+ register byte *p = pinfo->pic;
|
||
+
|
||
+ /* Since this is a 1-plane image, avoid a lot of errant nonsense in the
|
||
+ JasPer Library by sequentially reading all of the data into our buffer
|
||
+ directly.
|
||
+ */
|
||
+ do if ((i = (*c->ops_->read_)(c->obj_,(char *)p,bufsize)) <= 0)
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,i < 0 ? read_err : truncated,fbasename,
|
||
+ jp2_kind);
|
||
+ goto L1;
|
||
+ }
|
||
+ while ((p += i),(bufsize -= i) > 0);
|
||
+ }
|
||
+ else /* RGB color image */
|
||
+ {
|
||
+
|
||
+ /* Reading color images is inefficient because JPEG 2000 wants to partition
|
||
+ file data into separate image planes (colors), while XV wants data
|
||
+ samples from each plane to be interleaved as 3-byte pixels. Apparently
|
||
+ the fastest method consists of 3 passes through the XV image buffer,
|
||
+ into which we insert the bytes of each component.
|
||
+ */
|
||
+ i = 0;
|
||
+ do /* each color component */
|
||
+ { long npix = npixels;
|
||
+ register jas_stream_t *c = img->cmpts_[i]->stream_;
|
||
+ register byte *p = pinfo->pic + i;
|
||
+
|
||
+ do /* each pixel */
|
||
+ { register int b;
|
||
+
|
||
+ if ((b = jas_stream_getc(c)) < 0)
|
||
+ {
|
||
+ SetISTR(ISTR_WARNING,
|
||
+ (c->flags_ & JAS_STREAM_EOF) ? truncated : read_err,
|
||
+ fbasename,jp2_kind);
|
||
+ goto L1;
|
||
+ }
|
||
+ *p = b;
|
||
+ }
|
||
+ while ((p += 3),--npix > 0);
|
||
+ }
|
||
+ while (++i <= 2);
|
||
+ }
|
||
+ ok = 1; /* Success! */
|
||
+L1: jas_image_destroy(img);
|
||
+L2: (void)jas_stream_close(str);
|
||
+ free(iobuf);
|
||
+L3: return ok;
|
||
+}
|
||
+
|
||
+/* The following variables and subroutines are used when writing a JPEG 2000
|
||
+ file, which is done mainly using call-backs from "X Windows" widgets. The
|
||
+ most complicated part of this interface is: managing interactions with a
|
||
+ window to request the boat-loads of options that the JasPer Library supports.
|
||
+ Start by defining subwindow sizes, plus indices into several arrays of
|
||
+ corresponding widget-state variables.
|
||
+
|
||
+ IMPLEMENTATION NOTES: The following dimensions create a tall, thin window
|
||
+ which appears to have considerable empty space at the
|
||
+ bottom. Before you complain, click the Precinct Height menu button in order
|
||
+ to the tall pop-up subwindow that it generates. If the parent window is made
|
||
+ shorter, then this pop-up will be clipped, which is an ugly nuisance. I
|
||
+ don't know how to make the pop-up visible outside its parent's borders; do
|
||
+ you? If there's some way to make "X Windows" do this, then we might consider
|
||
+ making the parent shorter.
|
||
+
|
||
+ Note that there is currently no mechanism to program the no. of intermediate
|
||
+ layers used by the encoder, or their rates. This is potentially a large and
|
||
+ complicated data-entry problem, and perhaps someday we can invent a clever
|
||
+ solution using the rest of the parent window's space.
|
||
+*/
|
||
+# define JP2KW 275 /* Window width, in pixels */
|
||
+# define JP2KH 400 /* Window height, in pixels */
|
||
+# define BUTTW 51 /* Button width, in pixels (odd for half-toning) */
|
||
+# define BUTTH 20 /* Button height, in pixels */
|
||
+# define MENUW 75 /* Menu-button width, in pixels (odd for half-toning) */
|
||
+# define MENUH 24 /* Menu-button height, in pixels */
|
||
+# define RBUTH 20 /* Radio button height, in pixels */
|
||
+# define RBUTW 51 /* Radio button width, in pixels (odd for half-toning) */
|
||
+# define TEXTH (LINEHIGH+5) /* Text subwindow height, in pixels */
|
||
+# define TEXTW 75 /* Text subwindow width, in pixels */
|
||
+
|
||
+# define J_BOK 0 /* Boolean "Ok" button */
|
||
+# define J_BCANC 1 /* Boolean "Cancel" button */
|
||
+# define J_NBUTT 2 /* No. of regular button widgets */
|
||
+
|
||
+# define J_CSOP 0 /* Boolean encoding-style option buttons */
|
||
+# define J_CEPH 1
|
||
+# define J_CLAZY 2
|
||
+# define J_CTERM 3
|
||
+# define J_CSEGS 4
|
||
+# define J_CVCAU 5
|
||
+# define J_CPTRM 6
|
||
+# define J_CRSTP 7
|
||
+# define J_NCHKB 8 /* No. of check-box button widgets */
|
||
+
|
||
+# define J_MCBXW 0 /* 1-of-N menu-selection buttons */
|
||
+# define J_MCBXH 1
|
||
+# define J_MPREW 2
|
||
+# define J_MPREH 3
|
||
+# define J_MPROG 4
|
||
+# define J_NMENU 5 /* No. of menu-button widgets */
|
||
+
|
||
+# define J_TGBIT 0 /* (Unsigned numeric) string subwindows */
|
||
+# define J_TRES 1
|
||
+# define J_TRATE 2
|
||
+# define J_NTEXT 3 /* No. of text subwindows */
|
||
+
|
||
+static BUTT button[J_NBUTT];
|
||
+static CBUTT chkbut[J_NCHKB];
|
||
+static MBUTT menu[J_NMENU];
|
||
+static RBUTT *radio;
|
||
+static Window text[J_NTEXT];
|
||
+static int colorType, format, textval[J_NTEXT];
|
||
+static const char *ProgList[]={"lrcp","rlcp","rpcl","pcrl","cprl"};
|
||
+
|
||
+void CreateJP2KW(void)
|
||
+{
|
||
+ static const char EXP2_0[] ={ "1"}, /* Successive powers of 2 */
|
||
+ EXP2_1[] ={ "2"},
|
||
+ EXP2_2[] ={ "4"},
|
||
+ EXP2_3[] ={ "8"},
|
||
+ EXP2_4[] ={ "16"},
|
||
+ EXP2_5[] ={ "32"},
|
||
+ EXP2_6[] ={ "64"},
|
||
+ EXP2_7[] ={ "128"},
|
||
+ EXP2_8[] ={ "256"},
|
||
+ EXP2_9[] ={ "512"},
|
||
+ EXP2_10[]={ "1024"},
|
||
+ EXP2_11[]={ "2048"},
|
||
+ EXP2_12[]={ "4096"},
|
||
+ EXP2_13[]={ "8192"},
|
||
+ EXP2_14[]={"16384"},
|
||
+ EXP2_15[]={"32768"};
|
||
+ static const char *CBoxList[]=
|
||
+ {
|
||
+ EXP2_1 ,EXP2_2 ,EXP2_3 ,EXP2_4 ,EXP2_5,EXP2_6 ,EXP2_7 ,EXP2_8 ,EXP2_9,
|
||
+ EXP2_10,EXP2_11
|
||
+ };
|
||
+ static const char *PrecList[]=
|
||
+ {
|
||
+ EXP2_0,EXP2_1,EXP2_2 ,EXP2_3 ,EXP2_4 ,EXP2_5 ,EXP2_6 ,EXP2_7 ,
|
||
+ EXP2_8,EXP2_9,EXP2_10,EXP2_11,EXP2_12,EXP2_13,EXP2_14,EXP2_15
|
||
+ };
|
||
+ static const char hstr[]={"Height"}, wstr[]={"Width"};
|
||
+
|
||
+ if (!(jp2kW = CreateWindow( "xvjp2k"
|
||
+ , "XVjp2k"
|
||
+ , 0
|
||
+ , JP2KW
|
||
+ , JP2KH
|
||
+ , infofg
|
||
+ , infobg
|
||
+ , 0
|
||
+ )
|
||
+ )
|
||
+ ) FatalError("can't create JPEG 2000 window!");
|
||
+ XSelectInput(theDisp,jp2kW,ExposureMask|ButtonPressMask|KeyPressMask);
|
||
+
|
||
+ /* Create a row of 2 boolean-valued, regular buttons ("Ok" and "Cancel") in the
|
||
+ window's bottom right corner.
|
||
+ */
|
||
+ BTCreate(&button[J_BOK ],jp2kW,
|
||
+ JP2KW-2*BUTTW-20,JP2KH-10-BUTTH-1,BUTTW,BUTTH,
|
||
+ "Ok" ,infofg,infobg,hicol,locol);
|
||
+ BTCreate(&button[J_BCANC],jp2kW,
|
||
+ JP2KW- BUTTW-10,JP2KH-10-BUTTH-1,BUTTW,BUTTH,
|
||
+ "Cancel",infofg,infobg,hicol,locol);
|
||
+
|
||
+ /* Create a vertical column of 8 boolean-valued, check-box buttons (for
|
||
+ encoding-style options) down the window's left side.
|
||
+ */
|
||
+ CBCreate(&chkbut[J_CSOP] ,jp2kW,
|
||
+ 10,10+ASCENT+SPACING+2*LINEHIGH+0*BUTTH,
|
||
+ "sop" ,infofg,infobg,hicol,locol);
|
||
+ CBCreate(&chkbut[J_CEPH] ,jp2kW,
|
||
+ 10,10+ASCENT+SPACING+2*LINEHIGH+1*BUTTH,
|
||
+ "eph" ,infofg,infobg,hicol,locol);
|
||
+ CBCreate(&chkbut[J_CLAZY],jp2kW,
|
||
+ 10,10+ASCENT+SPACING+2*LINEHIGH+2*BUTTH,
|
||
+ "lazy" ,infofg,infobg,hicol,locol);
|
||
+ CBCreate(&chkbut[J_CTERM],jp2kW,
|
||
+ 10,10+ASCENT+SPACING+2*LINEHIGH+3*BUTTH,
|
||
+ "termall" ,infofg,infobg,hicol,locol);
|
||
+ CBCreate(&chkbut[J_CSEGS],jp2kW,
|
||
+ 10,10+ASCENT+SPACING+2*LINEHIGH+4*BUTTH,
|
||
+ "segsym" ,infofg,infobg,hicol,locol);
|
||
+ CBCreate(&chkbut[J_CVCAU],jp2kW,
|
||
+ 10,10+ASCENT+SPACING+2*LINEHIGH+5*BUTTH,
|
||
+ "vcausal" ,infofg,infobg,hicol,locol);
|
||
+ CBCreate(&chkbut[J_CPTRM],jp2kW,
|
||
+ 10,10+ASCENT+SPACING+2*LINEHIGH+6*BUTTH,
|
||
+ "pterm" ,infofg,infobg,hicol,locol);
|
||
+ CBCreate(&chkbut[J_CRSTP],jp2kW,
|
||
+ 10,10+ASCENT+SPACING+2*LINEHIGH+7*BUTTH,
|
||
+ "resetprob",infofg,infobg,hicol,locol);
|
||
+ /* Create text subwindows for unsigned decimal integer values. */
|
||
+
|
||
+ text[J_TGBIT] = XCreateSimpleWindow(theDisp,jp2kW,
|
||
+ JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+0*TEXTH,TEXTW,TEXTH,
|
||
+ 1,infofg,infobg);
|
||
+ XSelectInput(theDisp,text[J_TGBIT],ExposureMask|KeyPressMask);
|
||
+ text[J_TRES ] = XCreateSimpleWindow(theDisp,jp2kW,
|
||
+ JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+1*TEXTH,TEXTW,TEXTH,
|
||
+ 1,infofg,infobg);
|
||
+ XSelectInput(theDisp,text[J_TRES ],ExposureMask|KeyPressMask);
|
||
+ text[J_TRATE] = XCreateSimpleWindow(theDisp,jp2kW,
|
||
+ JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+2*TEXTH,TEXTW,TEXTH,
|
||
+ 1,infofg,infobg);
|
||
+ XSelectInput(theDisp,text[J_TRATE],ExposureMask|KeyPressMask);
|
||
+
|
||
+ /* Create a row of 2 boolean-valued radio buttons (for the "Rate" subwindow
|
||
+ value's unit of measure). The 1st button is "selected" by default.
|
||
+ */
|
||
+ radio = RBCreate(0,jp2kW,
|
||
+ JP2KW-19*RBUTW/8-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+3*TEXTH+4,
|
||
+ "Percent",infofg,infobg,hicol,locol);
|
||
+ (void)RBCreate(radio,jp2kW,
|
||
+ JP2KW-1*RBUTW-10 ,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+3*TEXTH+4,
|
||
+ "Bytes",infofg,infobg,hicol,locol);
|
||
+
|
||
+ /* Create pop-up menu-selection buttons after mapping the above subwindows,
|
||
+ since we don't want the pop-up menus mapped unless the corresponding button
|
||
+ is selected.
|
||
+ */
|
||
+ XMapSubwindows(theDisp,jp2kW);
|
||
+ MBCreate(&menu[J_MCBXW],jp2kW,
|
||
+ JP2KW-2*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+0*MENUH,MENUW,MENUH,
|
||
+ wstr ,CBoxList,sizeof CBoxList/sizeof *CBoxList,infofg,infobg,
|
||
+ hicol,locol);
|
||
+ MBCreate(&menu[J_MCBXH],jp2kW,
|
||
+ JP2KW-2*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+1*MENUH,MENUW,MENUH,
|
||
+ hstr ,CBoxList,sizeof CBoxList/sizeof *CBoxList,infofg,infobg,
|
||
+ hicol,locol);
|
||
+ MBCreate(&menu[J_MPREW],jp2kW,
|
||
+ JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+0*MENUH,MENUW,MENUH,
|
||
+ wstr ,PrecList,sizeof PrecList/sizeof *PrecList,infofg,infobg,
|
||
+ hicol,locol);
|
||
+ MBCreate(&menu[J_MPREH],jp2kW,
|
||
+ JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+1*MENUH,MENUW,MENUH,
|
||
+ hstr ,PrecList,sizeof PrecList/sizeof *PrecList,infofg,infobg,
|
||
+ hicol,locol);
|
||
+ MBCreate(&menu[J_MPROG],jp2kW,
|
||
+ JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+2*MENUH,MENUW,MENUH,
|
||
+ "Order",ProgList,sizeof ProgList/sizeof *ProgList,infofg,infobg,
|
||
+ hicol,locol);
|
||
+
|
||
+ /* Initialize values represented by widgets, which should correspond to default
|
||
+ compiled into the JasPer Library. Unfortunately, as of Version 1.701 there
|
||
+ is no easy way for an application to extract these from the library, so the
|
||
+ following code might get out of sync over time:
|
||
+ */
|
||
+ menu[J_MCBXW].hascheck = 1; menu[J_MCBXW].flags[ 5] = 1;
|
||
+ menu[J_MCBXH].hascheck = 1; menu[J_MCBXH].flags[ 5] = 1;
|
||
+ menu[J_MPREW].hascheck = 1; menu[J_MPREW].flags[15] = 1;
|
||
+ menu[J_MPREH].hascheck = 1; menu[J_MPREH].flags[15] = 1;
|
||
+ menu[J_MPROG].hascheck = 1; menu[J_MPROG].flags[ 0] = 1;
|
||
+ textval[J_TGBIT] = 2; /* No. of guard bits */
|
||
+ textval[J_TRES ] = 6; /* Max. no. of resolution levels */
|
||
+ textval[J_TRATE] = 100; /* Rate = 100% */
|
||
+}
|
||
+
|
||
+void JP2KSaveParams(int fmt,char *fname,int col) /* Save output-file parms */
|
||
+{
|
||
+ format = fmt; /* Desired file format: F_JPC|F_JP2 */
|
||
+ fbasename = fname; /* ->Output file path */
|
||
+ colorType = col; /* Desired color space: F_GREYSCALE|... */
|
||
+}
|
||
+
|
||
+static void StoreJP2K(char *options)
|
||
+{
|
||
+ static jas_image_cmptparm_t parm[3]= /* Image parameters */
|
||
+ {{0,0,1,1,0,0,8,0},{0,0,1,1,0,0,8,0},{0,0,1,1,0,0,8,0}};
|
||
+ static char nomem[]={"StoreJP2K: out of memory\n"},
|
||
+ write[]={"w"};
|
||
+ jas_image_t *img;
|
||
+ jas_stream_t *str;
|
||
+ FILE *fp, *fp2;
|
||
+ byte *pic, *r, *g, *b;
|
||
+ const char *filename;
|
||
+ char *iobuf = 0;
|
||
+ unsigned long imagesize;
|
||
+ jas_clrspc_t color_space;
|
||
+ int nc, w, h, pfree, ptype, error = 1;
|
||
+ register int i;
|
||
+
|
||
+ /* This is a generic subroutine for writing JPEG 2000 image files using the
|
||
+ JasPer Library. Our argument is an ASCII string, containing a Space (" ")-
|
||
+ separated sequence of encoder options that currently aren't well documented.
|
||
+ Most of the work is identical for both ".jpc" and ".jp2" files. Start by
|
||
+ verifying that the output file can be opened, then get an image buffer from
|
||
+ XV and begin crunching it into a suitable form for the JasPer Library.
|
||
+ */
|
||
+ if (!(fp = OpenOutFile(filename = fbasename))) return; /* Oops! */
|
||
+ setbuf(fp,0); /* We don't really use this file pointer for I/O; see below */
|
||
+ fbasename = BaseName(filename);
|
||
+ WaitCursor();
|
||
+ pic = GenSavePic(&ptype,&w,&h,&pfree,&nc,&r,&g,&b);
|
||
+ imagesize = w*h;
|
||
+ if (ptype == PIC24) imagesize *= 3;
|
||
+
|
||
+ /* As an optimization to save file space, even if our user didn't ask to store
|
||
+ a gray-scale image, check whether we could and, if so, do it anyway.
|
||
+ */
|
||
+ if (colorType != F_GREYSCALE) /* can we force a gray-scale image? */
|
||
+ {
|
||
+ if (ptype == PIC8)
|
||
+ {
|
||
+ i = nc;
|
||
+ while (--i >= 0 && r[i] == g[i] && r[i] == b[i]);
|
||
+ }
|
||
+ else /* PIC24 */
|
||
+ { register byte *p = pic + imagesize;
|
||
+
|
||
+ while ((p -= 3) >= pic && p[0] == p[1] && p[0] == p[2]);
|
||
+ i = p-pic;
|
||
+ };
|
||
+ if (i < 0) colorType = F_GREYSCALE; /* We made it all the way through */
|
||
+ };
|
||
+
|
||
+ /* If XV is currently color-mapping the image, make a color-mapped copy so that
|
||
+ the map needn't be transmitted in the output file.
|
||
+ */
|
||
+ if ((i = (colorType != F_GREYSCALE) << 1 | (ptype != PIC8)) != 3)
|
||
+ { byte *tmp = pic, *last = pic + imagesize;
|
||
+ register byte *from = tmp, *to = pic;
|
||
+
|
||
+ if (!(pic = (byte *)malloc(imagesize))) FatalError(nomem);
|
||
+ switch (i)
|
||
+ {
|
||
+
|
||
+ /* Color-map 8->8 bit image. */
|
||
+
|
||
+ case 0: do
|
||
+ {
|
||
+ i = *from;
|
||
+ *to++ = MONO(r[i],g[i],b[i]);
|
||
+ }
|
||
+ while (++from < last);
|
||
+ break;
|
||
+
|
||
+ /* Color-map 24->8 bit image. */
|
||
+
|
||
+ case 1: do *to++ = MONO(from[0],from[1],from[2]);
|
||
+ while ((from += 3) < last);
|
||
+ break;
|
||
+
|
||
+ /* Color-map 8->24 bit image. */
|
||
+
|
||
+ case 2: do
|
||
+ {
|
||
+ i = *from;
|
||
+ *to++ = r[i]; *to++ = g[i]; *to++ = b[i];
|
||
+ }
|
||
+ while (++from < last);
|
||
+ break;
|
||
+ };
|
||
+ if (pfree) free(tmp); /* Release the original image buffer if we can */
|
||
+ pfree = 1; /* Let the modified buffer be released later */
|
||
+ };
|
||
+
|
||
+ /* Initialize various image-file parameter variables. */
|
||
+
|
||
+ parm[0].width = w;
|
||
+ parm[0].height = h;
|
||
+ if (colorType == F_GREYSCALE) /* gray-scale image */
|
||
+ {
|
||
+ ptype = 1; /* No. of color planes */
|
||
+ color_space = JAS_CLRSPC_SGRAY;
|
||
+ }
|
||
+ else /* RGB color image */
|
||
+ {
|
||
+ ptype = 3; /* No. of color planes */
|
||
+ color_space = JAS_CLRSPC_SRGB;
|
||
+ parm[2].width = parm[1].width = parm[0].width;
|
||
+ parm[2].height = parm[1].height = parm[0].height;
|
||
+ };
|
||
+
|
||
+ /* Now comes a egregious hack: The JasPer Library will eventually want to
|
||
+ close the output file that it writes, but since XV opened the file, XV also
|
||
+ thinks it has the right to close the file! In order to pacify them both,
|
||
+ we duplicate the file pointer and let the JasPer Library have it, while we
|
||
+ retain the original for XV.
|
||
+
|
||
+ XXX This code is very UNIX-specific; what's an equivalent hack for Windows?
|
||
+ */
|
||
+ if (!(fp2 = (i = dup(fileno(fp))) >= 0 ? fdopen(i,write) : 0))
|
||
+ FatalError("StoreJP2K: can't duplicate output file pointer\n");
|
||
+ if (!(iobuf = SetBuf(fp2)))
|
||
+ {
|
||
+ (void)fclose(fp2);
|
||
+ FatalError(nomem);
|
||
+ };
|
||
+
|
||
+ /* Hand our output file to the JasPer Library and create an image object.
|
||
+ "jas_stream_close()" will eventually close our output file, so only do it
|
||
+ explicitly if no stream can be created. If everything looks copacetic,
|
||
+ then write our buffer contents to the image components' streams.
|
||
+ */
|
||
+ if (!(str = jas_stream_freopen(filename,write,fp2)))
|
||
+ {
|
||
+ (void)fclose(fp2);
|
||
+ FatalError("StoreJP2K: can't open output stream\n");
|
||
+ };
|
||
+ if (!(img = jas_image_create(ptype,parm,color_space))) goto L2;
|
||
+ if (ptype == 1)
|
||
+ { register jas_stream_t *c = img->cmpts_[0]->stream_;
|
||
+ register byte *p = pic;
|
||
+
|
||
+ /* Since this is a 1-plane image, avoid a lot of errant nonsense in the
|
||
+ JasPer Library by sequentially writing all of the data directly from our
|
||
+ buffer.
|
||
+ */
|
||
+ jas_image_setcmpttype(img,0,JAS_IMAGE_CT_GRAY_Y);
|
||
+ img->cmpts_[0]->type_ = JAS_IMAGE_CT_GRAY_Y;
|
||
+ do if ((i = (*c->ops_->write_)(c->obj_,(char *)p,imagesize)) <= 0)
|
||
+ goto L1;
|
||
+ while ((p += i),(imagesize -= i) > 0);
|
||
+ if (jas_stream_flush(c) < 0) goto L1;
|
||
+ }
|
||
+ else /* RGB color image */
|
||
+ {
|
||
+
|
||
+ /* Writing color images is inefficient because JPEG 2000 wants to partition
|
||
+ file data into separate image planes (colors), while XV wants data
|
||
+ samples from each plane to be interleaved as 3-byte pixels. Apparently
|
||
+ the fastest method consists of 3 passes through the XV image buffer,
|
||
+ from which we extract the bytes of each component.
|
||
+ */
|
||
+ i = 0;
|
||
+ do /* each color component */
|
||
+ { long npix = imagesize/3;
|
||
+ register jas_stream_t *c = img->cmpts_[i]->stream_;
|
||
+ register byte *p = pic + i;
|
||
+
|
||
+ jas_image_setcmpttype(img,i,i+JAS_IMAGE_CT_RGB_R);
|
||
+ do if (jas_stream_putc(c,*p) < 0) goto L1;
|
||
+ while ((p += 3),--npix > 0);
|
||
+ if (jas_stream_flush(c) < 0) goto L1;
|
||
+ }
|
||
+ while (++i <= 2);
|
||
+ };
|
||
+ if ( (*(format == F_JPC ? jpc_encode : jp2_encode))(img,str,options) >= 0
|
||
+ && jas_stream_flush(str) >= 0
|
||
+ ) error = 0; /* Success! */
|
||
+L1: jas_image_destroy(img);
|
||
+L2: (void)jas_stream_close(str);
|
||
+ if (iobuf) free(iobuf);
|
||
+ if (pfree) free(pic);
|
||
+ if (!CloseOutFile(fp,filename,error)) DirBox(0);
|
||
+ SetCursors(-1);
|
||
+}
|
||
+
|
||
+void JP2KDialog(int vis)
|
||
+{
|
||
+ if ((jp2kUp = vis)) CenterMapWindow(jp2kW,0,0,JP2KW,JP2KH);
|
||
+ else XUnmapWindow(theDisp,jp2kW);
|
||
+}
|
||
+
|
||
+static void TWRedraw(Window w,unsigned int val)
|
||
+{
|
||
+ char buf[11];
|
||
+ register int i;
|
||
+
|
||
+ /* Draw a 1-line numeric text string in the specified window, representing the
|
||
+ argument value as a left-justified unsigned decimal integer, followed by a
|
||
+ "cursor" icon.
|
||
+ */
|
||
+ sprintf(buf,"%u",val);
|
||
+ if (ctrlColor) XClearArea(theDisp,w,2,2,TEXTW-4,TEXTH-4,False);
|
||
+ else XClearWindow(theDisp,w);
|
||
+ Draw3dRect(w,0,0,TEXTW-1,TEXTH-1,R3D_IN,2,hicol,locol,infobg);
|
||
+ XSetForeground(theDisp,theGC,infofg);
|
||
+ XDrawString(theDisp,w,theGC,3,ASCENT+3,buf,i = strlen(buf));
|
||
+
|
||
+ /* Draw a "cursor" icon after the numeric string. */
|
||
+
|
||
+ i = XTextWidth(mfinfo,buf,i);
|
||
+ XDrawLine(theDisp,w,theGC,i+3,2 ,i+3,2+CHIGH+1);
|
||
+ XDrawLine(theDisp,w,theGC,i+3,2+CHIGH+1,i+5,2+CHIGH+3);
|
||
+ XDrawLine(theDisp,w,theGC,i+3,2+CHIGH+1,i+1,2+CHIGH+3);
|
||
+}
|
||
+
|
||
+int JP2KCheckEvent(register XEvent *xev)
|
||
+{
|
||
+ int ok = 0;
|
||
+
|
||
+ /* Check whether the argument "X Windows" event is for one of our subwindows.
|
||
+ If it is, handle the event and return 1; otherwise, return 0.
|
||
+ */
|
||
+ if (!jp2kUp) return 0;
|
||
+ switch (xev->type)
|
||
+ { KeySym ks;
|
||
+ int len;
|
||
+ char buf[128];
|
||
+ register int i;
|
||
+
|
||
+ /* Throw away excess "expose" events for "dumb" windows. */
|
||
+
|
||
+ case Expose :
|
||
+# define E ((XExposeEvent *)xev)
|
||
+ if (E->window == jp2kW)
|
||
+ { XRectangle rect;
|
||
+
|
||
+ rect.x = E->x ; rect.y = E->y ;
|
||
+ rect.width = E->width; rect.height = E->height;
|
||
+ XSetClipRectangles(theDisp,theGC,0,0,&rect,1,Unsorted);
|
||
+ XSetForeground(theDisp,theGC,infofg);
|
||
+ XSetBackground(theDisp,theGC,infobg);
|
||
+ i = sizeof button/sizeof *button;
|
||
+ while (--i >= 0) BTRedraw(&button[i]);
|
||
+ i = sizeof chkbut/sizeof *chkbut;
|
||
+ while (--i >= 0) CBRedraw(&chkbut[i]);
|
||
+ i = sizeof menu/sizeof *menu;
|
||
+ while (--i >= 0) MBRedraw(&menu[i]);
|
||
+ RBRedraw(radio,-1);
|
||
+ DrawString(jp2kW,10,10+ASCENT,"Save JPEG 2000 File...");
|
||
+ DrawString(jp2kW,10,10+ASCENT+2*LINEHIGH,"Style options:");
|
||
+ DrawString(jp2kW,JP2KW-2*MENUW-10,10+ASCENT+2*LINEHIGH,
|
||
+ "Coding Blk");
|
||
+ DrawString(jp2kW,JP2KW-1*MENUW-10,10+ASCENT+2*LINEHIGH,
|
||
+ " Precinct");
|
||
+ DrawString(jp2kW,
|
||
+ JP2KW-2*MENUW-10,10+ASCENT+SPACING+3*LINEHIGH+2*MENUH,
|
||
+ "Progression:");
|
||
+ DrawString(jp2kW,
|
||
+ JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+0*TEXTH,
|
||
+ "Guard bits:");
|
||
+ DrawString(jp2kW,
|
||
+ JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+1*TEXTH,
|
||
+ "Res levels:");
|
||
+ DrawString(jp2kW,
|
||
+ JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+2*TEXTH,
|
||
+ "Rate:");
|
||
+ XSetClipMask(theDisp,theGC,None);
|
||
+ ok = 1;
|
||
+ break;
|
||
+ };
|
||
+ i = sizeof text/sizeof *text;
|
||
+ while (--i >= 0 && E->window != text[i]);
|
||
+ if (i >= 0)
|
||
+ {
|
||
+ TWRedraw(E->window,textval[i]);
|
||
+ ok = 1;
|
||
+ };
|
||
+ break;
|
||
+# undef E
|
||
+
|
||
+ /* Check whether the user pressed one of our buttons. */
|
||
+
|
||
+ case ButtonPress:
|
||
+# define E ((XButtonEvent *)xev)
|
||
+ if (E->button == Button1 && E->window == jp2kW)
|
||
+ { register int j;
|
||
+
|
||
+ ok = 1; /* Check whether a regular button was pressed */
|
||
+ i = sizeof button/sizeof *button;
|
||
+ while ( --i >= 0
|
||
+ && !PTINRECT(E->x,E->y,button[i].x,button[i].y,button[i].w,button[i].h)
|
||
+ );
|
||
+ if (i >= 0) /* our button was pressed */
|
||
+ { char options[1024];
|
||
+ register char *p;
|
||
+ register const char *q;
|
||
+
|
||
+ if (!BTTrack(&button[i])) break; /* Ignore it */
|
||
+ if (i != J_BOK) /* must be "Cancel" button */
|
||
+ {
|
||
+ JP2KDialog(0);
|
||
+ break;
|
||
+ };
|
||
+
|
||
+ /* Our user hit the "Ok" button. At this point, we have an ugly
|
||
+ job to do: JasPer Library encoder options must be specified
|
||
+ as an ASCII string of Space (" ")-separated <tag>[=<value>]
|
||
+ entries, so we must collect the values of all of our widgets
|
||
+ and subwindows, determine whether our user has requested any
|
||
+ non-default values, then build the string only for the JasPer
|
||
+ Library to immediately tear it apart again. Yechh!
|
||
+ */
|
||
+ if ((unsigned)textval[J_TGBIT]-1 > 7)
|
||
+ {
|
||
+ OpenAlert("No. of guard bits must be 1-8");
|
||
+ sleep(3);
|
||
+ CloseAlert();
|
||
+ break;
|
||
+ };
|
||
+ if ((unsigned)textval[J_TRES ] <= 0)
|
||
+ {
|
||
+ OpenAlert("Maximum resolution levels must be >= 1");
|
||
+ sleep(3);
|
||
+ CloseAlert();
|
||
+ break;
|
||
+ };
|
||
+
|
||
+ /* XXX Should we check and complain if the rate is zero?
|
||
+ JasPer Library Version 1.701 apparently accepts that
|
||
+ value, even though it seems kinda weird.
|
||
+ */
|
||
+ p = options;
|
||
+ i = 0;
|
||
+ do if ((j = MBWhich(&menu[i])) != 5)
|
||
+ { static const char *parm[2] =
|
||
+ {"cblkwidth=%u", "cblkheight=%u"};
|
||
+
|
||
+ if (p > options) *p++ = ' ';
|
||
+ sprintf(p,parm[i-J_MCBXW],++j);
|
||
+ while (*++p);
|
||
+ }
|
||
+ while (++i <= J_MCBXH);
|
||
+ do if ((j = MBWhich(&menu[i])) < 15)
|
||
+ { static const char *parm[2] =
|
||
+ {"prcwidth=%u", "prcheight=%u"};
|
||
+
|
||
+ if (p > options) *p++ = ' ';
|
||
+ sprintf(p,parm[i-J_MPREW],j);
|
||
+ while (*++p);
|
||
+ }
|
||
+ while (++i <= J_MPREH);
|
||
+ if ((j = MBWhich(&menu[i])))
|
||
+ {
|
||
+ if (p > options) *p++ = ' ';
|
||
+ *p++ = 'p'; *p++ = 'r'; *p++ = 'g'; *p = '=';
|
||
+ q = ProgList[j];
|
||
+ while ((*++p = *q++));
|
||
+ };
|
||
+ if ((i = textval[J_TRES ]) != 6)
|
||
+ {
|
||
+ if (p > options) *p++ = ' ';
|
||
+ sprintf(p,"numrlvls=%u",i);
|
||
+ while (*++p);
|
||
+ };
|
||
+ i = 0;
|
||
+ do if (chkbut[i].val) /* append this encoding option */
|
||
+ {
|
||
+ if (p > options) *p++ = ' ';
|
||
+ q = chkbut[i].str;
|
||
+ while ((*p++ = *q++));
|
||
+ *--p = '\000';
|
||
+ }
|
||
+ while (++i < sizeof chkbut/sizeof *chkbut);
|
||
+ if ((i = textval[J_TGBIT]) != 2)
|
||
+ {
|
||
+ if (p > options) *p++ = ' ';
|
||
+ sprintf(p,"numgbits=%u",i);
|
||
+ while (*++p);
|
||
+ };
|
||
+ if ((i = textval[J_TRATE]) != 100)
|
||
+ {
|
||
+ if (p > options) *p++ = ' ';
|
||
+ *p++ = 'r'; *p++ = 'a'; *p++ = 't'; *p++ = 'e';
|
||
+ *p++ = '=';
|
||
+ if (i) /* non-zero rate */
|
||
+ {
|
||
+ if (RBWhich(radio)) sprintf(p,"%uB",i); /* # Bytes */
|
||
+ else /* the value is a percentage */
|
||
+ {
|
||
+ if (i > 100) i = 200; /* => Raw size + 1 */
|
||
+ sprintf(p,"%u.%.2u",i/100,i%100);
|
||
+ }
|
||
+ while (*++p);
|
||
+ }
|
||
+ else /* rate = 0 */
|
||
+ {
|
||
+
|
||
+ /* XXX This is apparently valid, since JasPer Library
|
||
+ Version 1.701 doesn't complain about it.
|
||
+ */
|
||
+ *p++ = '0';
|
||
+ *p = '\000';
|
||
+ }
|
||
+ };
|
||
+ StoreJP2K(options); /* Finally, do the *real* work! */
|
||
+ JP2KDialog(0);
|
||
+ p = GetDirFullName();
|
||
+ if (!ISPIPE(*p))
|
||
+ {
|
||
+ XVCreatedFile(p);
|
||
+ StickInCtrlList(0);
|
||
+ };
|
||
+ break;
|
||
+ };
|
||
+
|
||
+ /* See whether a check-box button was pressed. */
|
||
+
|
||
+ i = sizeof chkbut/sizeof *chkbut;
|
||
+ while (--i >= 0 && !CBClick(&chkbut[i],E->x,E->y));
|
||
+ if (i >= 0) /* our button was pressed */
|
||
+ {
|
||
+ (void)CBTrack(&chkbut[i]);
|
||
+ break;
|
||
+ };
|
||
+
|
||
+ /* See whether a menu button was pressed. */
|
||
+
|
||
+ i = sizeof menu/sizeof *menu;
|
||
+ while (--i >= 0 && !MBClick(&menu[i],E->x,E->y));
|
||
+ if (i >= 0) /* our button was pressed */
|
||
+ { register int j;
|
||
+
|
||
+ if ((j = MBTrack(&menu[i])) >= 0)
|
||
+ {
|
||
+ switch (i)
|
||
+ {
|
||
+
|
||
+ /* The JasPer Library constrains a coding box's area
|
||
+ (width x height) to be <= 4096 pixels, so if this
|
||
+ button-press would violate that condition, then
|
||
+ quietly limit the box's orthogonal dimension by just
|
||
+ enough to compensate.
|
||
+ */
|
||
+ case J_MCBXH:
|
||
+ case J_MCBXW: if (MBWhich(&menu[!i]) + j >= 10)
|
||
+ MBSelect(&menu[!i],10 - j);
|
||
+ };
|
||
+ MBSelect(&menu[i],j);
|
||
+ MBSetActive(&menu[i],1);
|
||
+ };
|
||
+ break;
|
||
+ };
|
||
+
|
||
+ /* See whether a radio button was pressed. */
|
||
+
|
||
+ if ( (i = RBClick(radio,E->x,E->y)) >= 0 /* button pressed */
|
||
+ && RBTrack(radio,i)
|
||
+ )
|
||
+ {
|
||
+ RBSelect(radio,i);
|
||
+ RBSetActive(radio,i,1);
|
||
+ };
|
||
+ break;
|
||
+ };
|
||
+ XBell(theDisp,50);
|
||
+ break;
|
||
+# undef E
|
||
+
|
||
+ /* Translate a few key-press events into simulated button events. */
|
||
+
|
||
+ case KeyPress :
|
||
+# define E ((XKeyEvent *)xev)
|
||
+ buf[len = XLookupString(E,buf,sizeof buf,&ks,0)] = '\000';
|
||
+ RemapKeyCheck(ks,buf,&len);
|
||
+ if (E->window == jp2kW)
|
||
+ {
|
||
+ ok = 1;
|
||
+ if (len > 0)
|
||
+ switch (buf[0])
|
||
+ {
|
||
+ case '\r' :
|
||
+ case '\n' : FakeButtonPress(&button[J_BOK ]);
|
||
+ break;
|
||
+ case '\033': FakeButtonPress(&button[J_BCANC]);
|
||
+ };
|
||
+ break;
|
||
+ };
|
||
+ i = sizeof text/sizeof *text;
|
||
+ while (--i >= 0 && E->window != text[i]);
|
||
+ if (i >= 0) /* a key was pressed in our text window */
|
||
+ { int oldval = textval[i]; /* Save this subwindow's old value */
|
||
+ register int c, j = 0;
|
||
+
|
||
+ /* This is a *very* simple text-input editing loop that assembles an
|
||
+ an unsigned integer from successive ASCII decimal digits, typed
|
||
+ into one of our 1-line subwindows. For convenience, the only
|
||
+ character recognized is Backspace.
|
||
+ */
|
||
+ ok = 1;
|
||
+ L: if (j >= len) break;
|
||
+ if ((unsigned)(c = buf[j++] - '0') <= 9)
|
||
+ {
|
||
+ TWRedraw(text[i],textval[i] = textval[i]*10 + c);
|
||
+ goto L;
|
||
+ };
|
||
+ if ((c += '0') == '\b')
|
||
+ {
|
||
+ TWRedraw(text[i],textval[i] = textval[i]/10);
|
||
+ goto L;
|
||
+ };
|
||
+ textval[i] = oldval;
|
||
+ };
|
||
+ XBell(theDisp,50);
|
||
+# undef E
|
||
+ };
|
||
+ return ok;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+void
|
||
+VersionInfoJP2K() /* GRR 20070304 */
|
||
+{
|
||
+ fprintf(stderr, " Compiled with libjasper %s; using libjasper %s.\n",
|
||
+ JAS_VERSION, jas_getversion());
|
||
+}
|
||
+
|
||
+#endif /* HAVE_JP2K */
|
||
diff -u -r --new-file xv-3.10a.orig/xvmag.c xv-3.10a/xvmag.c
|
||
--- xv-3.10a.orig/xvmag.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvmag.c 2005-04-18 00:56:58.000000000 -0500
|
||
@@ -0,0 +1,866 @@
|
||
+/*
|
||
+ * xvmag.c - load routine for `MAG' format pictures.
|
||
+ *
|
||
+ * The `MAG' format is used by many Japanese personal computer users.
|
||
+ * This program is based on MAGBIBLE.DOC which is the specification
|
||
+ * for `MAG' format written by Woody RINN. It is written in Japanese,
|
||
+ * and exists in some anon-ftp sites.
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+#include <setjmp.h>
|
||
+
|
||
+#ifdef HAVE_MAG
|
||
+
|
||
+typedef unsigned short data16;
|
||
+
|
||
+struct mag {
|
||
+ jmp_buf jmp;
|
||
+ FILE *fp;
|
||
+ long fsize;
|
||
+ int m_256, m_dig, m_8, m_200;
|
||
+ int x1, y1, x2, y2, left_pad, right_pad;
|
||
+ int p_width, p_height, width, height;
|
||
+ long h_off, a_off, a_size, b_off, b_size, p_off, p_size;
|
||
+ byte *a, *b, *p;
|
||
+};
|
||
+
|
||
+static void mag_open_file PARM((struct mag*, char*));
|
||
+static void mag_read_check_data PARM((struct mag*));
|
||
+static void mag_read_comment PARM((struct mag*, char**));
|
||
+static void mag_read_header PARM((struct mag*));
|
||
+static void mag_read_palette PARM((struct mag*, byte*, byte*, byte*));
|
||
+static void mag_read_flags PARM((struct mag*));
|
||
+static void mag_read_pixel_data PARM((struct mag*));
|
||
+static void mag_expand_body PARM((struct mag*, byte**));
|
||
+
|
||
+static void mag_compress_data PARM((struct mag*, byte*));
|
||
+static void mag_write_check_data PARM((struct mag*));
|
||
+static void mag_write_comment PARM((struct mag*, char *));
|
||
+static void mag_write_palette PARM((struct mag*, int,
|
||
+ byte*, byte*, byte*, int));
|
||
+static void mag_write_flags PARM((struct mag*));
|
||
+static void mag_write_pixel_data PARM((struct mag*));
|
||
+static void mag_write_header PARM((struct mag*));
|
||
+static void mag_set_double_word PARM((long, byte *));
|
||
+
|
||
+static void mag_init_info PARM((struct mag*));
|
||
+static void mag_cleanup_mag_info PARM((struct mag*, int));
|
||
+static void mag_cleanup_pinfo PARM((PICINFO*));
|
||
+static void mag_memory_error PARM((char*, char*));
|
||
+static void mag_error PARM((struct mag*, int));
|
||
+static void mag_file_error PARM((struct mag*, int));
|
||
+static void mag_file_warning PARM((struct mag*, int));
|
||
+static void mag_show_struct PARM((struct mag*));
|
||
+static void *mag_malloc PARM((size_t, char*));
|
||
+static void *mag_realloc PARM((void*, size_t, char*));
|
||
+
|
||
+
|
||
+static char *mag_id = "MAKI02 ";
|
||
+static struct{
|
||
+ int dx, dy;
|
||
+}points[16] = {
|
||
+ { 0, 0}, { 1, 0}, { 2, 0}, { 4, 0},
|
||
+ { 0, 1}, { 1, 1},
|
||
+ { 0, 2}, { 1, 2}, { 2, 2},
|
||
+ { 0, 4}, { 1, 4}, { 2, 4},
|
||
+ { 0, 8}, { 1, 8}, { 2, 8},
|
||
+ { 0, 16},
|
||
+};
|
||
+static int try[15] = {1, 4, 5, 6, 7, 9, 10, 2, 8, 11, 12, 13, 14, 3, 15};
|
||
+
|
||
+static char *mag_msgs[] = {
|
||
+ NULL,
|
||
+#define MAG_OPEN 1
|
||
+ "can't open file",
|
||
+#define MAG_CORRUPT 2
|
||
+ "file currupted.",
|
||
+#define MAG_FORMAT 3
|
||
+ "not MAG format.",
|
||
+#define MAG_WRITE 4
|
||
+ "write failed.",
|
||
+};
|
||
+
|
||
+
|
||
+#define H4(x) (((int) (x) >> 4) & 0x0f) /* operates on a byte */
|
||
+#define L4(x) ((x) & 0x0f)
|
||
+#define H8(x) (((x) >> 8) & 0xff) /* operates on a data16 */
|
||
+#define L8(x) ((x) & 0xff)
|
||
+
|
||
+#define error(msgnum) longjmp(mi->jmp, msgnum)
|
||
+
|
||
+
|
||
+/* The main routine to load a MAG file. */
|
||
+int LoadMAG(fname, pinfo)
|
||
+ char *fname;
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ struct mag mag;
|
||
+ int e;
|
||
+
|
||
+ if(DEBUG) fputs("LoadMAG:\n", stderr);
|
||
+
|
||
+ pinfo->comment = NULL;
|
||
+ mag_init_info(&mag);
|
||
+ if((e = setjmp(mag.jmp)) != 0){
|
||
+ /* When an error occurs, comes here. */
|
||
+ mag_cleanup_mag_info(&mag, 0);
|
||
+ mag_cleanup_pinfo(pinfo);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ mag_open_file(&mag, fname);
|
||
+ mag_read_check_data(&mag);
|
||
+ mag_read_comment(&mag, &pinfo->comment);
|
||
+ mag_read_header(&mag);
|
||
+ mag_read_palette(&mag, pinfo->r, pinfo->g, pinfo->b);
|
||
+ mag_read_flags(&mag);
|
||
+ mag_read_pixel_data(&mag);
|
||
+ mag_expand_body(&mag, &pinfo->pic);
|
||
+
|
||
+ pinfo->w = pinfo->normw = mag.width;
|
||
+ pinfo->h = pinfo->normh = mag.height;
|
||
+ pinfo->type = PIC8;
|
||
+ pinfo->frmType = F_MAG;
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ sprintf(pinfo->fullInfo, "MAG, %d colors%s (%ld bytes)",
|
||
+ mag.m_256 ? 256 : (mag.m_8 ? 8 : 16),
|
||
+ mag.m_200 ? ", aspect 0.5" : "", mag.fsize);
|
||
+ sprintf(pinfo->shrtInfo, "%dx%d MAG", mag.width, mag.height);
|
||
+ if(mag.m_200)
|
||
+ normaspect = 0.5;
|
||
+
|
||
+ mag_cleanup_mag_info(&mag, 0);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static void mag_open_file(mi, fname)
|
||
+ struct mag *mi;
|
||
+ char *fname;
|
||
+{
|
||
+ if((mi->fp = fopen(fname, "rb")) == NULL)
|
||
+ mag_file_error(mi, MAG_OPEN);
|
||
+ fseek(mi->fp, (size_t) 0, SEEK_END);
|
||
+ mi->fsize = ftell(mi->fp);
|
||
+ fseek(mi->fp, (size_t) 0, SEEK_SET);
|
||
+}
|
||
+
|
||
+static void mag_read_check_data(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ char buffer[8];
|
||
+
|
||
+ if(fread(buffer, (size_t) 8, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_error(mi, MAG_CORRUPT);
|
||
+ if(strncmp(buffer, mag_id, (size_t) 8) != 0)
|
||
+ mag_error(mi, MAG_FORMAT);
|
||
+}
|
||
+
|
||
+static void mag_read_comment(mi, p)
|
||
+ struct mag *mi;
|
||
+ char **p;
|
||
+{
|
||
+ int max = -1, i = 0;
|
||
+ int c;
|
||
+
|
||
+ while((c = fgetc(mi->fp)) != EOF){
|
||
+ if(c == 0x1a)
|
||
+ break;
|
||
+ if(max < i){
|
||
+ max += 16;
|
||
+ *p = mag_realloc(*p, (size_t) max + 1, "mag_read_comment#1");
|
||
+ }
|
||
+ (*p)[i++] = c;
|
||
+ }
|
||
+
|
||
+ if(c == EOF)
|
||
+ mag_file_error(mi, MAG_CORRUPT);
|
||
+
|
||
+ if(max < i){
|
||
+ *p = mag_realloc(*p, (size_t) max + 2, "mag_read_comment#2");
|
||
+ }
|
||
+ if(i > 24){
|
||
+ (*p)[i] = '\0';
|
||
+ strcpy(*p, &(*p)[24]);
|
||
+ }else{
|
||
+ (*p)[0] = '\0';
|
||
+ }
|
||
+}
|
||
+
|
||
+static void mag_read_header(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ byte buf[32];
|
||
+
|
||
+ mi->h_off = ftell(mi->fp);
|
||
+
|
||
+ if(fread(buf, (size_t) 32, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_error(mi, MAG_CORRUPT);
|
||
+
|
||
+ mi->m_256 = buf[3] & 0x80;
|
||
+ mi->m_dig = buf[3] & 0x04;
|
||
+ mi->m_8 = buf[3] & 0x02;
|
||
+ mi->m_200 = buf[3] & 0x01;
|
||
+
|
||
+ mi->x1 = buf[ 4] + buf[ 5] * 256;
|
||
+ mi->y1 = buf[ 6] + buf[ 7] * 256;
|
||
+ mi->x2 = buf[ 8] + buf[ 9] * 256;
|
||
+ mi->y2 = buf[10] + buf[11] * 256;
|
||
+
|
||
+#define get_dword(a, b, c, d) \
|
||
+ ((long)(a) << 24 | (long)(b) << 16 | (long)(c) << 8 | (long)(d))
|
||
+
|
||
+ mi->a_off = get_dword(buf[15], buf[14], buf[13], buf[12]);
|
||
+ mi->b_off = get_dword(buf[19], buf[18], buf[17], buf[16]);
|
||
+ mi->b_size = get_dword(buf[23], buf[22], buf[21], buf[20]);
|
||
+ mi->p_off = get_dword(buf[27], buf[26], buf[25], buf[24]);
|
||
+ mi->p_size = get_dword(buf[31], buf[30], buf[29], buf[28]);
|
||
+#undef get_dword
|
||
+
|
||
+ mi->a_size = mi->b_off - mi->a_off;
|
||
+ mi->a_off += mi->h_off;
|
||
+ mi->b_off += mi->h_off;
|
||
+ mi->p_off += mi->h_off;
|
||
+
|
||
+ mi->width = mi->x2 - mi->x1 + 1;
|
||
+ mi->height = mi->y2 - mi->y1 + 1;
|
||
+ mi->left_pad = mi->x1 & 07;
|
||
+ mi->right_pad = 07 - (mi->x2 & 07);
|
||
+ mi->x1 -= mi->left_pad; /* x1 = 8m */
|
||
+ mi->x2 += mi->right_pad; /* x2 = 8n+7 */
|
||
+ mi->p_width = ((mi->x2 + 1) - mi->x1) / (mi->m_256 ? 2 : 4);
|
||
+ mi->p_height = (mi->y2 + 1) - mi->y1;
|
||
+
|
||
+ if(DEBUG) mag_show_struct(mi);
|
||
+}
|
||
+
|
||
+static void mag_read_palette(mi, r, g, b)
|
||
+ struct mag *mi;
|
||
+ byte *r, *g, *b;
|
||
+{
|
||
+ int num_palettes;
|
||
+ byte *buf;
|
||
+
|
||
+ if(mi->m_256)
|
||
+ num_palettes = 256;
|
||
+ else
|
||
+ num_palettes = 16;
|
||
+
|
||
+ buf = mag_malloc((size_t)num_palettes * 3, "mag_read_palette");
|
||
+
|
||
+ if(fread(buf, (size_t) 3, (size_t) num_palettes, mi->fp) != num_palettes){
|
||
+ free(buf);
|
||
+ mag_file_error(mi, MAG_CORRUPT);
|
||
+ }
|
||
+
|
||
+ for(num_palettes--; num_palettes >= 0; num_palettes--){
|
||
+ g[num_palettes] = buf[num_palettes * 3 ];
|
||
+ r[num_palettes] = buf[num_palettes * 3 + 1];
|
||
+ b[num_palettes] = buf[num_palettes * 3 + 2];
|
||
+ }
|
||
+
|
||
+ free(buf);
|
||
+}
|
||
+
|
||
+static void mag_read_flags(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ mi->a = mag_malloc((size_t) mi->a_size, "mag_read_flags#1");
|
||
+ mi->b = mag_malloc((size_t) mi->b_size, "mag_read_flags#2");
|
||
+
|
||
+ fseek(mi->fp, mi->a_off, SEEK_SET);
|
||
+ if(fread(mi->a, (size_t) mi->a_size, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_warning(mi, MAG_CORRUPT);
|
||
+ if(fread(mi->b, (size_t) mi->b_size, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_warning(mi, MAG_CORRUPT);
|
||
+}
|
||
+
|
||
+static void mag_read_pixel_data(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ mi->p = mag_malloc((size_t) mi->p_size, "mag_read_pixel_data");
|
||
+
|
||
+ fseek(mi->fp, mi->p_off, SEEK_SET);
|
||
+ if(fread(mi->p, (size_t) mi->p_size, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_warning(mi, MAG_CORRUPT);
|
||
+}
|
||
+
|
||
+/* MAG expanding routine */
|
||
+static void mag_expand_body(mi, pic0)
|
||
+ struct mag *mi;
|
||
+ byte **pic0;
|
||
+{
|
||
+ int ai, bi, fi, pi;
|
||
+ int px, py, x, y;
|
||
+ byte *flag;
|
||
+ byte mask;
|
||
+ data16 *pixel0;
|
||
+
|
||
+ flag = mag_malloc((size_t) mi->p_width / 2, "mag_expand_body#1");
|
||
+ *pic0 = mag_malloc((size_t) mi->width * mi->height, "mag_expand_body#2"); // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ pixel0 = mag_malloc((size_t) 2 * mi->p_width * 17, "mag_expand_body#3"); // GRR POSSIBLE OVERFLOW / FIXME
|
||
+
|
||
+#define pixel(x, y) pixel0[(y) % 17 * mi->p_width + (x)]
|
||
+
|
||
+ ai = bi = pi = 0;
|
||
+ mask = 0x80;
|
||
+ for(y = py = 0; py < mi->p_height; py++){
|
||
+ for(fi = 0; fi < mi->p_width / 2; fi++){
|
||
+ if(py == 0){
|
||
+ if(mi->a[ai] & mask)
|
||
+ flag[fi] = mi->b[bi++];
|
||
+ else
|
||
+ flag[fi] = 0;
|
||
+ }else{
|
||
+ if(mi->a[ai] & mask)
|
||
+ flag[fi] ^= mi->b[bi++];
|
||
+ }
|
||
+ if((mask >>= 1) == 0){
|
||
+ mask = 0x80;
|
||
+ ai++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for(px = fi = 0; fi < mi->p_width / 2; fi++){
|
||
+ int f = H4(flag[fi]);
|
||
+ if(f == 0){
|
||
+ pixel(px, py) = mi->p[pi] + mi->p[pi + 1] * 256;
|
||
+ px++;
|
||
+ pi+=2;
|
||
+ }else{
|
||
+ int dx = points[f].dx, dy = points[f].dy;
|
||
+ pixel(px, py) = pixel(px - dx, py - dy);
|
||
+ px++;
|
||
+ }
|
||
+
|
||
+ f = L4(flag[fi]);
|
||
+ if(f == 0){
|
||
+ pixel(px, py) = mi->p[pi] + mi->p[pi + 1] * 256;
|
||
+ px++;
|
||
+ pi+=2;
|
||
+ }else{
|
||
+ int dx = points[f].dx, dy = points[f].dy;
|
||
+ pixel(px, py) = pixel(px - dx, py - dy);
|
||
+ px++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+#define inside(x) ((unsigned int)(x) < mi->width)
|
||
+#define pic(x, y) (*pic0)[(y) * mi->width + (x)]
|
||
+ for(x = -mi->left_pad, px = 0; px < mi->p_width; px++){
|
||
+ data16 p = pixel(px, py);
|
||
+ if(mi->m_256){
|
||
+ if(inside(x))
|
||
+ pic(x, y) = L8(p);
|
||
+ x++;
|
||
+ if(inside(x))
|
||
+ pic(x, y) = H8(p);
|
||
+ x++;
|
||
+ }else{
|
||
+ if(inside(x))
|
||
+ pic(x, y) = H4(L8(p));
|
||
+ x++;
|
||
+ if(inside(x))
|
||
+ pic(x, y) = L4(L8(p));
|
||
+ x++;
|
||
+ if(inside(x))
|
||
+ pic(x, y) = H4(H8(p));
|
||
+ x++;
|
||
+ if(inside(x))
|
||
+ pic(x, y) = L4(H8(p));
|
||
+ x++;
|
||
+ }
|
||
+ }
|
||
+ y++;
|
||
+ }
|
||
+#undef pic
|
||
+#undef inside
|
||
+#undef pixel
|
||
+
|
||
+ free(flag);
|
||
+ free(pixel0);
|
||
+}
|
||
+
|
||
+
|
||
+/* The main routine to write a MAG file. */
|
||
+int WriteMAG(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
|
||
+ comment)
|
||
+ FILE *fp;
|
||
+ byte *pic;
|
||
+ int ptype, w, h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int numcols, colorstyle;
|
||
+ char *comment;
|
||
+{
|
||
+ byte rtemp[256], gtemp[256], btemp[256];
|
||
+ struct mag mag;
|
||
+ int e;
|
||
+
|
||
+ if(DEBUG) fputs("WriteMag\n", stderr);
|
||
+
|
||
+ mag_init_info(&mag);
|
||
+ mag.fp = fp;
|
||
+
|
||
+ if(ptype == PIC24){
|
||
+ if(!(pic = Conv24to8(pic, w, h, 256, rtemp, gtemp, btemp)))
|
||
+ mag_memory_error("Conv24to8", "WriteMAG");
|
||
+ rmap = rtemp;
|
||
+ gmap = gtemp;
|
||
+ bmap = btemp;
|
||
+ numcols = 256;
|
||
+ mag.m_256 = 1;
|
||
+ }else{
|
||
+ if(numcols > 16)
|
||
+ mag.m_256 = 1;
|
||
+ }
|
||
+
|
||
+ if((e = setjmp(mag.jmp)) != 0){
|
||
+ /* When an error occurs, comes here. */
|
||
+ mag_cleanup_mag_info(&mag, 1);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ mag.x2 = w - 1;
|
||
+ mag.y2 = h - 1;
|
||
+ mag.right_pad = 07 - (mag.x2 & 07);
|
||
+ mag.p_width = (w + mag.right_pad) / (mag.m_256 ? 2 : 4);
|
||
+ mag.p_height = h;
|
||
+ mag.width = w;
|
||
+ mag.height = h;
|
||
+ mag.a_size = (mag.p_width * mag.p_height + 15) / 16; /* x/2/8 */ // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ if(mag.a_size % 2)
|
||
+ mag.a_size++;
|
||
+
|
||
+ mag_compress_data(&mag, pic);
|
||
+ mag_write_check_data(&mag);
|
||
+ mag_write_comment(&mag, comment);
|
||
+
|
||
+ mag.h_off = ftell(mag.fp);
|
||
+
|
||
+ mag_write_palette(&mag, numcols, rmap, gmap, bmap,
|
||
+ colorstyle == F_GREYSCALE);
|
||
+ mag_write_flags(&mag);
|
||
+ mag_write_pixel_data(&mag);
|
||
+ mag_write_header(&mag);
|
||
+
|
||
+ mag_cleanup_mag_info(&mag, 1);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* MAG compressing routine */
|
||
+static void mag_compress_data(mi, pic0)
|
||
+ struct mag *mi;
|
||
+ byte *pic0;
|
||
+{
|
||
+ int ai, bi, pi, i;
|
||
+ int bmax, pmax;
|
||
+ byte mask;
|
||
+ byte *flag0;
|
||
+ data16 *pixel0;
|
||
+ int px, py, x, y;
|
||
+
|
||
+ pixel0 = mag_malloc((size_t) 2 * mi->p_width * mi->p_height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "mag_compress_data#1");
|
||
+ flag0 = mag_malloc((size_t) mi->p_width * mi->p_height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "mag_compress_data#2");
|
||
+
|
||
+#define pic(x, y) pic0[(y) * mi->width + (x)]
|
||
+ /* convert dots to pixels */
|
||
+ i = 0;
|
||
+ for(y = py = 0; py < mi->p_height; py++){
|
||
+ for(x = px = 0; px < mi->p_width; px++){
|
||
+ data16 p = 0;
|
||
+ if(mi->m_256){
|
||
+ if(x < mi->width)
|
||
+ p += pic(x, y);
|
||
+ x++;
|
||
+ if(x < mi->width)
|
||
+ p += pic(x, y) * 256;
|
||
+ x++;
|
||
+ }else{
|
||
+ if(x < mi->width)
|
||
+ p += pic(x, y) * 16;
|
||
+ x++;
|
||
+ if(x < mi->width)
|
||
+ p += pic(x, y);
|
||
+ x++;
|
||
+ if(x < mi->width)
|
||
+ p += pic(x, y) * 4096;
|
||
+ x++;
|
||
+ if(x < mi->width)
|
||
+ p += pic(x, y) * 256;
|
||
+ x++;
|
||
+ }
|
||
+ pixel0[i++] = p;
|
||
+ }
|
||
+ y++;
|
||
+ }
|
||
+#undef pic
|
||
+
|
||
+#define pixel(x, y) pixel0[(y) * mi->p_width + (x)]
|
||
+#define flag(x, y) flag0[(y) * mi->p_width + (x)]
|
||
+ /* get flags */
|
||
+ pmax = pi = 0;
|
||
+ for(py = 0; py < mi->p_height; py++){
|
||
+ for(px = 0; px < mi->p_width; px++){
|
||
+ int t;
|
||
+ for(t = 0; t < 15; t++){
|
||
+ int dx = points[try[t]].dx, dy = points[try[t]].dy;
|
||
+ if(dx <= px && dy <= py){
|
||
+ if(pixel(px - dx, py - dy) == pixel(px, py))
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if(t < 15){
|
||
+ flag(px, py) = try[t];
|
||
+ }else{
|
||
+ flag(px, py) = 0;
|
||
+ if(pmax <= pi + 1){
|
||
+ pmax += 128;
|
||
+ mi->p = mag_realloc(mi->p, (size_t) pmax,
|
||
+ "mag_compress_data#3");
|
||
+ }
|
||
+ mi->p[pi++] = L8(pixel(px, py));
|
||
+ mi->p[pi++] = H8(pixel(px, py));
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+#undef flag
|
||
+#undef pixel
|
||
+
|
||
+ /* pack 2 flags into 1 byte */
|
||
+ for(i = 0; i < mi->p_width / 2 * mi->p_height; i++)
|
||
+ flag0[i] = flag0[i * 2] * 16 + flag0[i * 2 + 1];
|
||
+
|
||
+#define flag(x, y) flag0[(y) * mi->p_width / 2 + (x)]
|
||
+ for(py = mi->p_height - 1; py >= 1; py--){
|
||
+ for(px = 0; px < mi->p_width / 2; px++)
|
||
+ flag(px, py) ^= flag(px, py - 1);
|
||
+ }
|
||
+#undef flag
|
||
+
|
||
+ mask = 0x80;
|
||
+ ai = bi = bmax = 0;
|
||
+ mi->a = mag_malloc((size_t) mi->a_size, "mag_compress_data#4"); // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ for(i = 0; i < mi->p_width / 2 * mi->p_height; i++){
|
||
+ if(flag0[i] == 0){
|
||
+ mi->a[ai] &= ~mask;
|
||
+ }else{
|
||
+ if(bmax == bi){
|
||
+ bmax += 128;
|
||
+ mi->b = mag_realloc(mi->b, (size_t) bmax,
|
||
+ "mag_compress_data#4");
|
||
+ }
|
||
+ mi->b[bi++] = flag0[i];
|
||
+ mi->a[ai] |= mask;
|
||
+ }
|
||
+
|
||
+ if((mask >>= 1) == 0){
|
||
+ mask = 0x80;
|
||
+ ai++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if(bi % 2)
|
||
+ bi++;
|
||
+ mi->b_size = bi;
|
||
+
|
||
+ mi->p_size = pi;
|
||
+
|
||
+ free(pixel0);
|
||
+ free(flag0);
|
||
+}
|
||
+
|
||
+static void mag_write_check_data(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ if(fwrite(mag_id, (size_t) 8, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+}
|
||
+
|
||
+static void mag_write_comment(mi, comment)
|
||
+ struct mag *mi;
|
||
+ char *comment;
|
||
+{
|
||
+ char *p;
|
||
+ int i;
|
||
+
|
||
+ if(fputs("XV ", mi->fp) == EOF)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+
|
||
+ if((p = (char *) getenv("USER")) == NULL)
|
||
+ p = "????????";
|
||
+ for(i = 5; i < 24; i++){
|
||
+ if(*p == '\0')
|
||
+ break;
|
||
+ if(fputc(*p++, mi->fp) == EOF)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+ }
|
||
+ for( ; i < 24; i++){
|
||
+ if(fputc(' ', mi->fp) == EOF)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+ }
|
||
+
|
||
+ if(comment){
|
||
+ int l = strlen(comment);
|
||
+ if(l > 0){
|
||
+ int i;
|
||
+ for(i = 0; i < l; i++){
|
||
+ if(comment[i] == 0x1a)
|
||
+ comment[i] = ' ';
|
||
+ }
|
||
+ if(fwrite(comment, (size_t) l, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if(fputc(0x1a, mi->fp) == EOF)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+}
|
||
+
|
||
+static void mag_write_palette(mi, num, r, g, b, grey)
|
||
+ struct mag *mi;
|
||
+ int num;
|
||
+ byte *r, *g, *b;
|
||
+ int grey;
|
||
+{
|
||
+ int i, left;
|
||
+ char buf[3];
|
||
+
|
||
+ fseek(mi->fp, 32L, SEEK_CUR); /* skip header area */
|
||
+ for(i = 0; i < num; i++){
|
||
+ buf[0] = *g++;
|
||
+ buf[1] = *r++;
|
||
+ buf[2] = *b++;
|
||
+ if(grey)
|
||
+ buf[0] = buf[1] = buf[2] = MONO(buf[1], buf[0], buf[2]);
|
||
+ if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+ }
|
||
+ if(num < 16){
|
||
+ left = 16 - num;
|
||
+ }else if(num == 16){
|
||
+ left = 0;
|
||
+ }else if(num < 256){
|
||
+ left = 256 - num;
|
||
+ }else if(num == 256){
|
||
+ left = 0;
|
||
+ }else
|
||
+ left = 0; /* shouldn't happen */
|
||
+
|
||
+ if(left > 0){
|
||
+ for(i = 0; i < left; i++){
|
||
+ if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void mag_write_flags(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ mi->a_off = ftell(mi->fp);
|
||
+ for(i = 0; i < mi->a_size; i++){
|
||
+ if(fputc(mi->a[i], mi->fp) == EOF)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+ }
|
||
+
|
||
+ mi->b_off = ftell(mi->fp);
|
||
+ for(i = 0; i < mi->b_size; i++){
|
||
+ if(fputc(mi->b[i], mi->fp) == EOF)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void mag_write_pixel_data(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ mi->p_off = ftell(mi->fp);
|
||
+ for(i = 0; i < mi->p_size; i++){
|
||
+ if(fputc(mi->p[i], mi->fp) == EOF)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void mag_write_header(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ byte buf[32];
|
||
+
|
||
+ if(DEBUG) mag_show_struct(mi);
|
||
+
|
||
+ mi->a_off -= mi->h_off;
|
||
+ mi->b_off -= mi->h_off;
|
||
+ mi->p_off -= mi->h_off;
|
||
+
|
||
+ buf[ 0] = buf[1] = buf[2] = 0;
|
||
+ buf[ 3] = (mi->m_256 ? 0x80 : 0);
|
||
+ buf[ 4] = buf[5] = 0;
|
||
+ buf[ 6] = buf[7] = 0;
|
||
+ buf[ 8] = L8(mi->x2);
|
||
+ buf[ 9] = H8(mi->x2);
|
||
+ buf[10] = L8(mi->y2);
|
||
+ buf[11] = H8(mi->y2);
|
||
+ mag_set_double_word(mi->a_off, &buf[12]);
|
||
+ mag_set_double_word(mi->b_off, &buf[16]);
|
||
+ mag_set_double_word(mi->b_size, &buf[20]);
|
||
+ mag_set_double_word(mi->p_off, &buf[24]);
|
||
+ mag_set_double_word(mi->p_size, &buf[28]);
|
||
+
|
||
+ fseek(mi->fp, mi->h_off, SEEK_SET);
|
||
+ if(fwrite(buf, (size_t) 32, (size_t) 1, mi->fp) != 1)
|
||
+ mag_file_error(mi, MAG_WRITE);
|
||
+}
|
||
+
|
||
+static void mag_set_double_word(n, p)
|
||
+ long n;
|
||
+ byte *p;
|
||
+{
|
||
+ p[0] = n % 256; /* ugly...anything wrong with shift/mask operations? */
|
||
+ p[1] = n / 256 % 256; /* (n >> 8) & 0xff */
|
||
+ p[2] = n / 256 / 256 % 256; /* (n >> 16) & 0xff */
|
||
+ p[3] = n / 256 / 256 / 256 % 256; /* (n >> 24) & 0xff */
|
||
+}
|
||
+
|
||
+/*
|
||
+ * The routines to initialize or clean up.
|
||
+ * mag_init_info:
|
||
+ * initializes a mag structure.
|
||
+ * mag_cleanup_mag_info:
|
||
+ * cleans up a mag structure.
|
||
+ * mag_cleanup_pinfo:
|
||
+ * cleans up a PICINFO structure.
|
||
+ */
|
||
+static void mag_init_info(mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ mi->fp = NULL;
|
||
+ mi->fsize = 0;
|
||
+ mi->m_256 = mi->m_dig = mi->m_8 = mi->m_200 = 0;
|
||
+ mi->x1 = mi->y1 = mi->x2 = mi->y2 = 0;
|
||
+ mi->left_pad = mi->right_pad = 0;
|
||
+ mi->p_width = mi->p_height = mi->width = mi->height = 0;
|
||
+ mi->h_off = mi->p_off = mi->p_size = 0;
|
||
+ mi->a_off = mi->a_size = mi->b_off = mi->b_size = 0;
|
||
+ mi->a = NULL;
|
||
+ mi->b = NULL;
|
||
+ mi->p = NULL;
|
||
+}
|
||
+
|
||
+static void mag_cleanup_mag_info(mi, writing)
|
||
+ struct mag *mi;
|
||
+ int writing;
|
||
+{
|
||
+ if(mi->fp && !writing)
|
||
+ fclose(mi->fp);
|
||
+ if(mi->a)
|
||
+ free(mi->a);
|
||
+ if(mi->b)
|
||
+ free(mi->b);
|
||
+ if(mi->p)
|
||
+ free(mi->p);
|
||
+}
|
||
+
|
||
+static void mag_cleanup_pinfo(pinfo)
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ if(pinfo->comment){
|
||
+ free(pinfo->comment);
|
||
+ pinfo->comment = NULL;
|
||
+ }
|
||
+ if(pinfo->pic){
|
||
+ free(pinfo->pic);
|
||
+ pinfo->pic = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Error handler.
|
||
+ * mag_memory_error:
|
||
+ * shows an error message, and terminates.
|
||
+ * mag_error:
|
||
+ * shows an non-file error message, and jumps to the entry for errors.
|
||
+ * mag_file_error:
|
||
+ * shows an file error message, and jumps to the entry for errors.
|
||
+ * mag_file_warning:
|
||
+ * shows an file warning message.
|
||
+ */
|
||
+static void mag_memory_error(scm, fn)
|
||
+ char *scm, *fn;
|
||
+{
|
||
+ char buf[128];
|
||
+ sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn);
|
||
+ FatalError(buf);
|
||
+}
|
||
+
|
||
+static void mag_error(mi, mn)
|
||
+ struct mag *mi;
|
||
+ int mn;
|
||
+{
|
||
+ SetISTR(ISTR_WARNING, "%s", mag_msgs[mn]);
|
||
+ longjmp(mi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void mag_file_error(mi, mn)
|
||
+ struct mag *mi;
|
||
+ int mn;
|
||
+{
|
||
+ if(feof(mi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", mag_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", mag_msgs[mn], ERRSTR(errno));
|
||
+ longjmp(mi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void mag_file_warning(mi, mn)
|
||
+ struct mag *mi;
|
||
+ int mn;
|
||
+{
|
||
+ if(feof(mi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", mag_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", mag_msgs[mn], ERRSTR(errno));
|
||
+}
|
||
+
|
||
+static void mag_show_struct (mi)
|
||
+ struct mag *mi;
|
||
+{
|
||
+ fprintf(stderr, " 256 colors: %s\n", mi->m_256 ? "true" : "false");
|
||
+ fprintf(stderr, " 8 colors: %s\n", mi->m_8 ? "true" : "false");
|
||
+ fprintf(stderr, " digital colors: %s\n", mi->m_dig ? "true" : "false");
|
||
+ fprintf(stderr, " aspect ratio: %f\n", mi->m_200 ? 0.5 : 1.0);
|
||
+ fprintf(stderr, " image size: %dx%d\n", mi->width, mi->height);
|
||
+ fprintf(stderr, " left pad: %d\n", mi->left_pad);
|
||
+ fprintf(stderr, " right pad: %d\n", mi->right_pad);
|
||
+ fprintf(stderr, " h_off: %ld\n", mi->h_off);
|
||
+ fprintf(stderr, " A: off:%ld, size:%ld\n", mi->a_off, mi->a_size);
|
||
+ fprintf(stderr, " B: off:%ld, size:%ld\n", mi->b_off, mi->b_size);
|
||
+ fprintf(stderr, " P: off:%ld, size:%ld\n", mi->p_off, mi->p_size);
|
||
+}
|
||
+
|
||
+/* Memory related routines. */
|
||
+static void *mag_malloc(n, fn)
|
||
+ size_t n;
|
||
+ char *fn;
|
||
+{
|
||
+ void *r = (void *) malloc(n);
|
||
+ if(r == NULL)
|
||
+ mag_memory_error("malloc", fn);
|
||
+ return r;
|
||
+}
|
||
+
|
||
+static void *mag_realloc(p, n, fn)
|
||
+ void *p;
|
||
+ size_t n;
|
||
+ char *fn;
|
||
+{
|
||
+ void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n);
|
||
+ if(r == NULL)
|
||
+ mag_memory_error("realloc", fn);
|
||
+ return r;
|
||
+}
|
||
+#endif /* HAVE_MAG */
|
||
diff -u -r --new-file xv-3.10a.orig/xvmaki.c xv-3.10a/xvmaki.c
|
||
--- xv-3.10a.orig/xvmaki.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvmaki.c 2005-04-18 00:57:01.000000000 -0500
|
||
@@ -0,0 +1,794 @@
|
||
+/*
|
||
+ * xvmaki.c - load routine for `MAKI' format pictures.
|
||
+ *
|
||
+ * The `MAKI' format was used by some Japanese personal computer users.
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+#include <setjmp.h>
|
||
+
|
||
+#ifdef HAVE_MAKI
|
||
+
|
||
+typedef unsigned short data16;
|
||
+typedef unsigned int data32;
|
||
+
|
||
+struct maki_info {
|
||
+ jmp_buf jmp;
|
||
+ FILE *fp;
|
||
+ long fsize;
|
||
+ int x0, y0, x1, y1;
|
||
+ int width, height;
|
||
+ float aspect;
|
||
+ long fb_size;
|
||
+ long pa_size, pb_size;
|
||
+ int m_maki01b, m_200, m_dig8;
|
||
+ data16 ext_flag;
|
||
+ byte *fa, *fb, *pa, *pb;
|
||
+ byte *vs;
|
||
+ int numcols;
|
||
+ byte *forma, *formb;
|
||
+};
|
||
+
|
||
+
|
||
+static void maki_open_file PARM((struct maki_info*, char*));
|
||
+static void maki_check_id PARM((struct maki_info*));
|
||
+static void maki_skip_comment PARM((struct maki_info*));
|
||
+static void maki_read_header PARM((struct maki_info*));
|
||
+static void maki_read_palette PARM((struct maki_info*,
|
||
+ byte*, byte*, byte*));
|
||
+static void maki_read_flags PARM((struct maki_info*));
|
||
+static void maki_read_pixel_data PARM((struct maki_info*));
|
||
+static void maki_expand_virtual_screen PARM((struct maki_info*));
|
||
+static void maki_expand_pixel_data PARM((struct maki_info*, byte**));
|
||
+static void maki_init_info PARM((struct maki_info*));
|
||
+
|
||
+static void maki_make_pixel_data PARM((struct maki_info*, byte*));
|
||
+static void maki_make_virtual_screen PARM((struct maki_info*));
|
||
+static void maki_make_flags PARM((struct maki_info*));
|
||
+static void maki_write_check_id PARM((struct maki_info*));
|
||
+static void maki_write_comment PARM((struct maki_info*));
|
||
+static void maki_write_header PARM((struct maki_info*));
|
||
+static void maki_write_palette PARM((struct maki_info*,
|
||
+ byte*, byte*, byte*, int));
|
||
+static void maki_write_flags PARM((struct maki_info*));
|
||
+static void maki_write_pixel_data PARM((struct maki_info*));
|
||
+
|
||
+static void maki_cleanup_maki_info PARM((struct maki_info*, int));
|
||
+static void maki_cleanup_pinfo PARM((PICINFO*));
|
||
+static void maki_memory_error PARM((char*, char*));
|
||
+static void maki_error PARM((struct maki_info*, int));
|
||
+static void maki_file_error PARM((struct maki_info*, int));
|
||
+static void maki_file_warning PARM((struct maki_info*, int));
|
||
+static void maki_show_maki_info PARM((struct maki_info*));
|
||
+static void *maki_malloc PARM((size_t, char*));
|
||
+static void *maki_realloc PARM((void *, size_t, char*));
|
||
+
|
||
+static char maki_id_a[] = "MAKI01A ";
|
||
+static char maki_id_b[] = "MAKI01B ";
|
||
+
|
||
+static char *maki_msgs[] = {
|
||
+ NULL,
|
||
+#define MAKI_OPEN 1
|
||
+ "can't open file.",
|
||
+#define MAKI_CORRUPT 2
|
||
+ "file corrupted.",
|
||
+#define MAKI_FORMAT 3
|
||
+ "not MAKI format.",
|
||
+#define MAKI_BAD_DATA 4
|
||
+ "bad data.",
|
||
+#define MAKI_COMMENT 5
|
||
+ "no '^Z' after comment.",
|
||
+#define MAKI_SIZE 6
|
||
+ "bad size.",
|
||
+#define MAKI_WRITE 7
|
||
+ "write failed.",
|
||
+};
|
||
+
|
||
+#define H4(b) ((b) >> 4 & 0xf)
|
||
+#define L4(b) ((b) & 0xf)
|
||
+#define error(msg_num) longjmp(mi->jmp, msg_num)
|
||
+
|
||
+int LoadMAKI(fname, pinfo)
|
||
+ char *fname;
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ struct maki_info maki;
|
||
+ int e;
|
||
+
|
||
+ if(DEBUG) fputs("LoadMAKI:\n", stderr);
|
||
+
|
||
+ pinfo->comment = NULL;
|
||
+ maki_init_info(&maki);
|
||
+ if((e = setjmp(maki.jmp)) != 0){
|
||
+ /* When an error occurs, comes here. */
|
||
+ maki_cleanup_maki_info(&maki, 0);
|
||
+ maki_cleanup_pinfo(pinfo);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ maki_open_file(&maki, fname);
|
||
+ maki_check_id(&maki);
|
||
+ maki_skip_comment(&maki);
|
||
+ maki_read_header(&maki);
|
||
+ maki_read_palette(&maki, pinfo->r, pinfo->g, pinfo->b);
|
||
+ maki_read_flags(&maki);
|
||
+ maki_read_pixel_data(&maki);
|
||
+ maki_expand_virtual_screen(&maki);
|
||
+ maki_expand_pixel_data(&maki, &pinfo->pic);
|
||
+
|
||
+ pinfo->w = pinfo->normw = maki.width;
|
||
+ pinfo->h = pinfo->normh = maki.height;
|
||
+ pinfo->type = PIC8;
|
||
+ pinfo->frmType = F_MAKI;
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ sprintf(pinfo->fullInfo, "MAKI, 16 colors (%ld bytes)", maki.fsize);
|
||
+ sprintf(pinfo->shrtInfo, "%dx%d MAKI", maki.width, maki.height);
|
||
+ normaspect = maki.aspect;
|
||
+
|
||
+ maki_cleanup_maki_info(&maki, 0);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static void maki_open_file(mi, fname)
|
||
+ struct maki_info *mi;
|
||
+ char *fname;
|
||
+{
|
||
+ if((mi->fp = fopen(fname, "rb")) == NULL)
|
||
+ maki_file_error(mi, MAKI_OPEN);
|
||
+ fseek(mi->fp, (size_t) 0, SEEK_END);
|
||
+ mi->fsize = ftell(mi->fp);
|
||
+ fseek(mi->fp, (size_t) 0, SEEK_SET);
|
||
+}
|
||
+
|
||
+static void maki_check_id(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ char buf[8];
|
||
+ if(fread(buf, (size_t) 8, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_CORRUPT);
|
||
+ if(strncmp(buf, maki_id_a, (size_t) 8) != 0 &&
|
||
+ strncmp(buf, maki_id_b, (size_t) 8) != 0)
|
||
+ maki_error(mi, MAKI_FORMAT);
|
||
+ mi->m_maki01b = (buf[6] == 'B');
|
||
+}
|
||
+
|
||
+static void maki_skip_comment(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ int i;
|
||
+ int c;
|
||
+
|
||
+ for(i = 0; i < 24; i++){
|
||
+ if((c = fgetc(mi->fp)) == EOF)
|
||
+ maki_file_error(mi, MAKI_CORRUPT);
|
||
+ if(c == '\032') /* ^Z, 0x1a */
|
||
+ break;
|
||
+ }
|
||
+ if(c != '\032')
|
||
+ maki_file_error(mi, MAKI_COMMENT);
|
||
+
|
||
+ fseek(mi->fp, 32L, SEEK_SET);
|
||
+}
|
||
+
|
||
+static void maki_read_header(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ byte buf[16];
|
||
+
|
||
+ if(fread(buf, (size_t) 16, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_CORRUPT);
|
||
+
|
||
+ mi->fb_size = (long)buf[ 0] << 8 | (long)buf[ 1];
|
||
+ mi->pa_size = (long)buf[ 2] << 8 | (long)buf[ 3];
|
||
+ mi->pb_size = (long)buf[ 4] << 8 | (long)buf[ 5];
|
||
+ mi->ext_flag = (long)buf[ 6] << 8 | (long)buf[ 7];
|
||
+ mi->x0 = (long)buf[ 8] << 8 | (long)buf[ 9];
|
||
+ mi->y0 = (long)buf[10] << 8 | (long)buf[11];
|
||
+ mi->x1 = (long)buf[12] << 8 | (long)buf[13];
|
||
+ mi->y1 = (long)buf[14] << 8 | (long)buf[15];
|
||
+
|
||
+ mi->width = mi->x1-- - mi->x0;
|
||
+ mi->height = mi->y1-- - mi->y0;
|
||
+ mi->m_200 = mi->ext_flag & 1;
|
||
+ mi->m_dig8 = mi->ext_flag & 2;
|
||
+ mi->aspect = mi->m_200 ? 0.5 : 1.0;
|
||
+
|
||
+ if(DEBUG) maki_show_maki_info(mi);
|
||
+}
|
||
+
|
||
+static void maki_read_palette(mi, r, g, b)
|
||
+ struct maki_info *mi;
|
||
+ byte *r, *g, *b;
|
||
+{
|
||
+ byte buf[48], *p;
|
||
+
|
||
+ if(fread(buf, (size_t) 48, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_CORRUPT);
|
||
+
|
||
+ for(p = buf; p < &buf[48]; ){
|
||
+ *g++ = *p++;
|
||
+ *r++ = *p++;
|
||
+ *b++ = *p++;
|
||
+ }
|
||
+}
|
||
+
|
||
+static void maki_read_flags(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ mi->fa = maki_malloc((size_t) 1000 , "maki_read_flags#1");
|
||
+ mi->fb = maki_malloc((size_t) mi->fb_size, "maki_read_flags#2");
|
||
+
|
||
+ if(fread(mi->fa, (size_t) 1000, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_warning(mi, MAKI_CORRUPT);
|
||
+ if(fread(mi->fb, (size_t) mi->fb_size, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_warning(mi, MAKI_CORRUPT);
|
||
+}
|
||
+
|
||
+static void maki_read_pixel_data(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ mi->pa = maki_malloc((size_t) mi->pa_size, "maki_read_pixel_data#1");
|
||
+ mi->pb = maki_malloc((size_t) mi->pb_size, "maki_read_pixel_data#2");
|
||
+
|
||
+ if(fread(mi->pa, (size_t) mi->pa_size, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_warning(mi, MAKI_CORRUPT);
|
||
+ if(fread(mi->pb, (size_t) mi->pb_size, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_warning(mi, MAKI_CORRUPT);
|
||
+}
|
||
+
|
||
+static void maki_expand_virtual_screen(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ int x, y, fai, fbi;
|
||
+ int bpl = mi->width / 2 / 8; /* bytes per line */
|
||
+ byte mask;
|
||
+ mi->vs = maki_malloc((size_t) bpl * mi->height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "maki_expand_virtual_screen");
|
||
+
|
||
+ fai = fbi = 0;
|
||
+ mask = 0x80;
|
||
+ for(y = 0; y < mi->height; y += 4){
|
||
+ for(x = 0; x < mi->width / 2; x += 4){
|
||
+ if(mi->fa[fai] & mask){
|
||
+ byte bh, bl;
|
||
+ bh = mi->fb[fbi++];
|
||
+ bl = mi->fb[fbi++];
|
||
+ if(x % 8 == 0){
|
||
+ mi->vs[ y * bpl + x / 8] = H4(bh) << 4;
|
||
+ mi->vs[(y + 1) * bpl + x / 8] = L4(bh) << 4;
|
||
+ mi->vs[(y + 2) * bpl + x / 8] = H4(bl) << 4;
|
||
+ mi->vs[(y + 3) * bpl + x / 8] = L4(bl) << 4;
|
||
+ }else{
|
||
+ mi->vs[ y * bpl + x / 8] |= H4(bh);
|
||
+ mi->vs[(y + 1) * bpl + x / 8] |= L4(bh);
|
||
+ mi->vs[(y + 2) * bpl + x / 8] |= H4(bl);
|
||
+ mi->vs[(y + 3) * bpl + x / 8] |= L4(bl);
|
||
+ }
|
||
+ }else{
|
||
+ if(x % 8 == 0){
|
||
+ mi->vs[ y * bpl + x / 8] = 0;
|
||
+ mi->vs[(y + 1) * bpl + x / 8] = 0;
|
||
+ mi->vs[(y + 2) * bpl + x / 8] = 0;
|
||
+ mi->vs[(y + 3) * bpl + x / 8] = 0;
|
||
+ }else{
|
||
+/* mi->vs[ y * bpl + x / 8] |= 0;
|
||
+ mi->vs[(y + 1) * bpl + x / 8] |= 0;
|
||
+ mi->vs[(y + 2) * bpl + x / 8] |= 0;
|
||
+ mi->vs[(y + 3) * bpl + x / 8] |= 0; */
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if((mask >>= 1) == 0){
|
||
+ mask = 0x80;
|
||
+ fai++;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void maki_expand_pixel_data(mi, pic)
|
||
+ struct maki_info *mi;
|
||
+ byte **pic;
|
||
+{
|
||
+ int x, y;
|
||
+ int vsi, pi, max_pi;
|
||
+ byte *p;
|
||
+ byte mask;
|
||
+ int gap;
|
||
+ *pic = maki_malloc((size_t) mi->width * mi->height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "maki_expand_pixel_data");
|
||
+
|
||
+ vsi = pi = 0;
|
||
+ p = mi->pa;
|
||
+ max_pi = mi->pa_size - 1;
|
||
+ mask = 0x80;
|
||
+ for(y = 0; y < mi->height; y++){
|
||
+ for(x = 0; x < mi->width; x += 2){
|
||
+ if(mi->vs[vsi] & mask){
|
||
+ if(pi > max_pi){
|
||
+ if(p == mi->pb)
|
||
+ maki_error(mi, MAKI_BAD_DATA);
|
||
+ pi = 0;
|
||
+ p = mi->pb;
|
||
+ max_pi = mi->pb_size - 1;
|
||
+ }
|
||
+ (*pic)[y * mi->width + x ] = H4(p[pi]);
|
||
+ (*pic)[y * mi->width + x + 1] = L4(p[pi]);
|
||
+ pi++;
|
||
+ }else{
|
||
+ (*pic)[y * mi->width + x ] = 0;
|
||
+ (*pic)[y * mi->width + x + 1] = 0;
|
||
+ }
|
||
+
|
||
+ if((mask >>= 1) == 0){
|
||
+ mask = 0x80;
|
||
+ vsi++;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ gap = mi->m_maki01b ? 4 : 2;
|
||
+
|
||
+ for(y = gap; y < mi->height; y++){
|
||
+ for(x = 0; x < mi->width; x++)
|
||
+ (*pic)[y * mi->width + x] ^= (*pic)[(y - gap) * mi->width + x];
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+int WriteMAKI(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle)
|
||
+ FILE *fp;
|
||
+ byte *pic;
|
||
+ int ptype, w, h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int numcols, colorstyle;
|
||
+{
|
||
+ byte rtemp[256], gtemp[256], btemp[256];
|
||
+ struct maki_info maki, *mi = &maki;
|
||
+ int e;
|
||
+
|
||
+ if(DEBUG) fputs("WriteMAKI:\n", stderr);
|
||
+
|
||
+ maki_init_info(&maki);
|
||
+ if((e = setjmp(maki.jmp)) != 0){
|
||
+ /* An error occurs */
|
||
+ maki_cleanup_maki_info(&maki, 1);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ if(w != 640 || h != 400) {
|
||
+ char str[512];
|
||
+ sprintf(str,"MAKI: %s Should be 640x400", maki_msgs[MAKI_SIZE]);
|
||
+ ErrPopUp(str, "\nBummer!");
|
||
+ maki_error(mi, MAKI_SIZE);
|
||
+ }
|
||
+
|
||
+ maki.fp = fp;
|
||
+ maki.width = w;
|
||
+ maki.height = h;
|
||
+ maki.x1 = w - 1;
|
||
+ maki.y1 = h - 1;
|
||
+
|
||
+ if(ptype == PIC24){
|
||
+ if(!(pic = Conv24to8(pic, w, h, 16, rtemp, gtemp, btemp)))
|
||
+ maki_memory_error("Conv24to8#1", "WriteMAKI");
|
||
+ rmap = rtemp;
|
||
+ gmap = gtemp;
|
||
+ bmap = btemp;
|
||
+ }else if(numcols > 16){
|
||
+ if(!(pic = Conv8to24(pic, w, h, rmap, gmap, bmap)))
|
||
+ maki_memory_error("Conv8to24", "WriteMAKI");
|
||
+ if(!(pic = Conv24to8(pic, w, h, 16, rtemp, gtemp, btemp)))
|
||
+ maki_memory_error("Conv24to8#2", "WriteMAKI");
|
||
+ rmap = rtemp;
|
||
+ gmap = gtemp;
|
||
+ bmap = btemp;
|
||
+ }else
|
||
+ maki.numcols = numcols;
|
||
+
|
||
+ maki_make_pixel_data(&maki, pic);
|
||
+ maki_make_virtual_screen(&maki);
|
||
+ maki_make_flags(&maki);
|
||
+ maki_write_check_id(&maki);
|
||
+ maki_write_comment(&maki);
|
||
+ maki_write_header(&maki);
|
||
+ maki_write_palette(&maki, rmap, gmap, bmap, colorstyle == F_GREYSCALE);
|
||
+ maki_write_flags(&maki);
|
||
+ maki_write_pixel_data(&maki);
|
||
+
|
||
+ maki_cleanup_maki_info(&maki, 1);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void maki_make_pixel_data(mi, pic)
|
||
+ struct maki_info *mi;
|
||
+ byte *pic;
|
||
+{
|
||
+ int x, y, i;
|
||
+ int nza, nzb;
|
||
+
|
||
+ mi->forma = maki_malloc((size_t) mi->width / 2 * mi->height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "maki_make_pixel_data#1");
|
||
+ mi->formb = maki_malloc((size_t) mi->width / 2 * mi->height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "maki_make_pixel_data#2");
|
||
+
|
||
+ for(y = 0; y < mi->height; y++){
|
||
+ for(x = 0; x < mi->width; x += 2){
|
||
+ byte b;
|
||
+ b = pic[y * mi->width + x] << 4 | pic[y * mi->width + x + 1];
|
||
+ mi->forma[y * mi->width / 2 + x / 2] = b;
|
||
+ mi->formb[y * mi->width / 2 + x / 2] = b;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for(y = mi->height - 1; y >= 2; y--){
|
||
+ for(x = 0; x < mi->width / 2; x++){
|
||
+ mi->forma[y * mi->width / 2 + x] ^=
|
||
+ mi->forma[(y - 2) * mi->width / 2 + x];
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for(y = mi->height - 1; y >= 4; y--){
|
||
+ for(x = 0; x < mi->width / 2; x++){
|
||
+ mi->formb[y * mi->width / 2 + x] ^=
|
||
+ mi->formb[(y - 4) * mi->width / 2 + x];
|
||
+ }
|
||
+ }
|
||
+
|
||
+ nza = nzb = 0;
|
||
+ for(i = 0; i < mi->width / 2 * mi->height; i++){
|
||
+ if(mi->forma[i] != 0)
|
||
+ nza++;
|
||
+ if(mi->formb[i] != 0)
|
||
+ nzb++;
|
||
+ }
|
||
+ if(nza > nzb){
|
||
+ mi->m_maki01b = 1;
|
||
+ free(mi->forma);
|
||
+ mi->forma = NULL;
|
||
+ }else{
|
||
+ mi->m_maki01b = 0;
|
||
+ free(mi->formb);
|
||
+ mi->formb = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
+static void maki_make_virtual_screen(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ int bpl = mi->width / 2 / 8;
|
||
+ int vsi, pai, pbi, max_pai, max_pbi;
|
||
+ byte mask;
|
||
+ byte *pixels;
|
||
+ int x, y;
|
||
+
|
||
+ mi->vs = maki_malloc((size_t) bpl * mi->height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "maki_make_virtual_screen#1");
|
||
+
|
||
+ if(mi->m_maki01b)
|
||
+ pixels = mi->formb;
|
||
+ else
|
||
+ pixels = mi->forma;
|
||
+
|
||
+ vsi = pai = pbi = 0;
|
||
+ max_pai = max_pbi = -1;
|
||
+ mask = 0x80;
|
||
+ for(y = 0; y < mi->height; y++){
|
||
+ for(x = 0; x < mi->width / 2; x++){
|
||
+ if(pixels[y * mi->width / 2 + x] == 0){
|
||
+ mi->vs[vsi] &= ~mask;
|
||
+ }else{
|
||
+ mi->vs[vsi] |= mask;
|
||
+ if(y < 200){
|
||
+ if(pai > max_pai){
|
||
+ max_pai += 1024;
|
||
+ mi->pa = maki_realloc(mi->pa, (size_t) max_pai + 1,
|
||
+ "maki_make_virtual_screen#2");
|
||
+ }
|
||
+ mi->pa[pai++] = pixels[y * mi->width / 2 + x];
|
||
+ }else{
|
||
+ if(pbi > max_pbi){
|
||
+ max_pbi += 1024;
|
||
+ mi->pb = maki_realloc(mi->pb, (size_t) max_pbi + 2,
|
||
+ "maki_make_virtual_screen#3");
|
||
+ }
|
||
+ mi->pb[pbi++] = pixels[y * mi->width / 2 + x];
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if((mask >>= 1) == 0){
|
||
+ mask = 0x80;
|
||
+ vsi++;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ mi->pa_size = pai;
|
||
+ mi->pb_size = pbi;
|
||
+}
|
||
+
|
||
+static void maki_make_flags(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ int bpl = mi->width / 2 / 8;
|
||
+ int fbi, max_fbi;
|
||
+ int fai;
|
||
+ int x, y;
|
||
+ byte mask;
|
||
+
|
||
+ mi->fa = maki_malloc((size_t) bpl * mi->height, "maki_make_flags#1"); // GRR POSSIBLE OVERFLOW / FIXME
|
||
+
|
||
+ fbi = fai = 0;
|
||
+ max_fbi = -1;
|
||
+ mask = 0x80;
|
||
+ for(y = 0; y < mi->height; y += 4){
|
||
+ for(x = 0; x < mi->width / 2; x += 4){
|
||
+ if(x % 8 == 0){
|
||
+ if(H4(mi->vs[ y * bpl + x / 8]) == 0 &&
|
||
+ H4(mi->vs[(y + 1) * bpl + x / 8]) == 0 &&
|
||
+ H4(mi->vs[(y + 2) * bpl + x / 8]) == 0 &&
|
||
+ H4(mi->vs[(y + 3) * bpl + x / 8]) == 0){
|
||
+ mi->fa[fai] &= ~mask;
|
||
+ }else{
|
||
+ mi->fa[fai] |= mask;
|
||
+ if(fbi + 1 > max_fbi){
|
||
+ max_fbi += 1024;
|
||
+ mi->fb = maki_realloc(mi->fb, (size_t) max_fbi + 1,
|
||
+ "maki_make_flags#2");
|
||
+ }
|
||
+ mi->fb[fbi++] = H4(mi->vs[ y * bpl + x / 8]) << 4
|
||
+ | H4(mi->vs[(y + 1) * bpl + x / 8]);
|
||
+ mi->fb[fbi++] = H4(mi->vs[(y + 2) * bpl + x / 8]) << 4
|
||
+ | H4(mi->vs[(y + 3) * bpl + x / 8]);
|
||
+ }
|
||
+ }else{
|
||
+ if(L4(mi->vs[ y * bpl + x / 8]) == 0 &&
|
||
+ L4(mi->vs[(y + 1) * bpl + x / 8]) == 0 &&
|
||
+ L4(mi->vs[(y + 2) * bpl + x / 8]) == 0 &&
|
||
+ L4(mi->vs[(y + 3) * bpl + x / 8]) == 0){
|
||
+ mi->fa[fai] &= ~mask;
|
||
+ }else{
|
||
+ mi->fa[fai] |= mask;
|
||
+ if(fbi + 1 > max_fbi){
|
||
+ max_fbi += 1024;
|
||
+ mi->fb = maki_realloc(mi->fb, (size_t) max_fbi + 1,
|
||
+ "maki_make_flags#3");
|
||
+ }
|
||
+ mi->fb[fbi++] = L4(mi->vs[ y * bpl + x / 8]) << 4
|
||
+ | L4(mi->vs[(y + 1) * bpl + x / 8]);
|
||
+ mi->fb[fbi++] = L4(mi->vs[(y + 2) * bpl + x / 8]) << 4
|
||
+ | L4(mi->vs[(y + 3) * bpl + x / 8]);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if((mask >>= 1) == 0){
|
||
+ mask = 0x80;
|
||
+ fai++;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ mi->fb_size = fbi;
|
||
+}
|
||
+
|
||
+static void maki_write_check_id(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ char *id = mi->m_maki01b ? maki_id_b : maki_id_a;
|
||
+ if(fwrite(id, (size_t) 8, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+}
|
||
+
|
||
+static void maki_write_comment(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ char buf[24];
|
||
+ char *p;
|
||
+ int i = 0;
|
||
+
|
||
+ strcpy(buf, "XV ");
|
||
+
|
||
+ if((p = (char *) getenv("USER")) == NULL)
|
||
+ p = "????????";
|
||
+ for(i = 5; i < 23; i++){
|
||
+ if(*p == '\0')
|
||
+ break;
|
||
+ buf[i] = *p++;
|
||
+ }
|
||
+ for( ; i < 23; i++)
|
||
+ buf[i] = ' ';
|
||
+
|
||
+ buf[i] = '\032'; /* ^Z, 0x1a */
|
||
+
|
||
+ if(fwrite(buf, (size_t) 24, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+}
|
||
+
|
||
+static void maki_write_header(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ byte buf[16];
|
||
+
|
||
+ if(DEBUG) maki_show_maki_info(mi);
|
||
+
|
||
+#define set_word(i, v) {buf[i]=(v)>>8&0xff;buf[i+1]=(v)&0xff;}
|
||
+ set_word(0, mi->fb_size);
|
||
+ set_word(2, mi->pa_size);
|
||
+ set_word(4, mi->pb_size);
|
||
+ set_word(6, mi->ext_flag);
|
||
+ set_word(8, mi->x0);
|
||
+ set_word(10, mi->y0);
|
||
+ set_word(12, mi->x1 + 1);
|
||
+ set_word(14, mi->y1 + 1);
|
||
+#undef set_word
|
||
+
|
||
+ if(fwrite(buf, (size_t) 16, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+}
|
||
+
|
||
+static void maki_write_palette(mi, r, g, b, grey)
|
||
+ struct maki_info *mi;
|
||
+ byte *r, *g, *b;
|
||
+ int grey;
|
||
+{
|
||
+ int i;
|
||
+ char buf[3];
|
||
+ for(i = 0; i < mi->numcols; i++){
|
||
+ buf[0] = *g++;
|
||
+ buf[1] = *r++;
|
||
+ buf[2] = *b++;
|
||
+ if(grey)
|
||
+ buf[0] = buf[1] = buf[2] = MONO(buf[1], buf[0], buf[2]);
|
||
+ if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+ }
|
||
+ for( ; i < 16; i++){
|
||
+ if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void maki_write_flags(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ int bpl = mi->width / 2 / 8;
|
||
+ if(fwrite(mi->fa, (size_t) bpl * mi->height / 16, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+
|
||
+ if(fwrite(mi->fb, (size_t) mi->fb_size, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+}
|
||
+
|
||
+static void maki_write_pixel_data(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ if(fwrite(mi->pa, (size_t) mi->pa_size, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+
|
||
+ if(fwrite(mi->pb, (size_t) mi->pb_size, (size_t) 1, mi->fp) != 1)
|
||
+ maki_file_error(mi, MAKI_WRITE);
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+static void maki_init_info(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ xvbzero((char *)mi, sizeof(struct maki_info));
|
||
+ mi->fp = NULL;
|
||
+ mi->fsize = 0;
|
||
+ mi->x0 = mi->y0 = mi->x1 = mi->y1 = 0;
|
||
+ mi->width = mi->height = 0;
|
||
+ mi->aspect = 1.0;
|
||
+ mi->fb_size = mi->pa_size = mi->pb_size = 0;
|
||
+ mi->m_maki01b = mi->m_200 = mi->m_dig8 = 0;
|
||
+ mi->ext_flag = 0;
|
||
+ mi->fa = mi->fb = mi->pa = mi->pb = NULL;
|
||
+ mi->vs = NULL;
|
||
+ mi->numcols = 16;
|
||
+ mi->forma = mi->formb = NULL;
|
||
+}
|
||
+
|
||
+static void maki_cleanup_maki_info(mi, writing)
|
||
+ struct maki_info *mi;
|
||
+ int writing;
|
||
+{
|
||
+ if(mi->fp && !writing)
|
||
+ fclose(mi->fp);
|
||
+ if(mi->fa)
|
||
+ free(mi->fa);
|
||
+ if(mi->fb)
|
||
+ free(mi->fb);
|
||
+ if(mi->pa)
|
||
+ free(mi->pa);
|
||
+ if(mi->pb)
|
||
+ free(mi->pb);
|
||
+ if(mi->vs)
|
||
+ free(mi->vs);
|
||
+ if(mi->forma)
|
||
+ free(mi->forma);
|
||
+ if(mi->formb)
|
||
+ free(mi->formb);
|
||
+}
|
||
+
|
||
+static void maki_cleanup_pinfo(pi)
|
||
+ PICINFO *pi;
|
||
+{
|
||
+ if(pi->pic){
|
||
+ free(pi->pic);
|
||
+ pi->pic = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
+static void maki_memory_error(scm, fn)
|
||
+ char *scm, *fn;
|
||
+{
|
||
+ char buf[128];
|
||
+ sprintf(buf, "%s: coulndn't allocate memory. (%s)", scm, fn);
|
||
+ FatalError(buf);
|
||
+}
|
||
+
|
||
+static void maki_error(mi, mn)
|
||
+ struct maki_info *mi;
|
||
+ int mn;
|
||
+{
|
||
+ SetISTR(ISTR_WARNING, "%s", maki_msgs[mn]);
|
||
+ longjmp(mi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void maki_file_error(mi, mn)
|
||
+ struct maki_info *mi;
|
||
+ int mn;
|
||
+{
|
||
+ if(feof(mi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", maki_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", maki_msgs[mn], ERRSTR(errno));
|
||
+ longjmp(mi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void maki_file_warning(mi, mn)
|
||
+ struct maki_info *mi;
|
||
+ int mn;
|
||
+{
|
||
+ if(feof(mi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", maki_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", maki_msgs[mn], ERRSTR(errno));
|
||
+}
|
||
+
|
||
+static void maki_show_maki_info(mi)
|
||
+ struct maki_info *mi;
|
||
+{
|
||
+ fprintf(stderr, " file size: %ld.\n", mi->fsize);
|
||
+ fprintf(stderr, " image size: %dx%d.\n", mi->width, mi->height);
|
||
+ fprintf(stderr, " aspect: %f.\n", mi->aspect);
|
||
+ fprintf(stderr, " flag B size: %ld.\n", mi->fb_size);
|
||
+ fprintf(stderr, " pixel data size: A:%ld, B:%ld.\n",
|
||
+ mi->pa_size, mi->pb_size);
|
||
+ fprintf(stderr, " MAKI01B: %s.\n", mi->m_maki01b ? "true" : "false");
|
||
+ fprintf(stderr, " 200 line mode: %s.\n", mi->m_200 ? "true" : "false");
|
||
+ fprintf(stderr, " digital 8 colors: %s.\n", mi->m_dig8 ? "true" : "false");
|
||
+}
|
||
+
|
||
+static void *maki_malloc(n, fn)
|
||
+ size_t n;
|
||
+ char *fn;
|
||
+{
|
||
+ void *r = (void *) malloc(n);
|
||
+ if(r == NULL)
|
||
+ maki_memory_error("malloc", fn);
|
||
+ return r;
|
||
+}
|
||
+
|
||
+static void *maki_realloc(p, n, fn)
|
||
+ void *p;
|
||
+ size_t n;
|
||
+ char *fn;
|
||
+{
|
||
+ void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n);
|
||
+ if(r == NULL)
|
||
+ maki_memory_error("realloc", fn);
|
||
+ return r;
|
||
+}
|
||
+#endif /* HAVE_MAKI */
|
||
diff -u -r --new-file xv-3.10a.orig/xvmgcsfx.c xv-3.10a/xvmgcsfx.c
|
||
--- xv-3.10a.orig/xvmgcsfx.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvmgcsfx.c 2007-04-15 17:02:32.000000000 -0500
|
||
@@ -0,0 +1,2276 @@
|
||
+/*
|
||
+ * $Id: xvmgcsfx.c,v 1.23 95/11/27 19:03:36 tin329 Exp Locker: tin329 $
|
||
+ * xvmgcsfx.c - Use the filters as input and output method.
|
||
+ *
|
||
+ * Features
|
||
+ * ========
|
||
+ * Use the filters as input and output method for load and save unsupported
|
||
+ * image format file. The filter command is recognized by definition of
|
||
+ * magic number or suffix in "~/.xv_mgcsfx" .
|
||
+ *
|
||
+ * Bugs
|
||
+ * ====
|
||
+ * There are many bugs.
|
||
+ * Let's go hunting for insects with an insect net. (it's all joke.)
|
||
+ *
|
||
+ * Author
|
||
+ * ======
|
||
+ * Tetsuya INOUE <tin329@chino.it.okayama-u.ac.jp>
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * Known Bugs and Todo / $B$"$l$3$l5$$K$J$k$3$H(B
|
||
+ *
|
||
+ * ~/.xv_mgcsfx $BFb(B
|
||
+ * $B!&Dj5A$,IT40A4$@$H%(%i!<(B (':'$B$N?t(B)$B!#(B
|
||
+ * $B!&%G%j%_%?$H$7$F(B ':' $B$r;H$&$N$G!"%9%?!<%H%"%C%W%U%!%$%kFb$G(B
|
||
+ * ':' $B$rMQ$$$FDj5A$O$G$-$J$$!#(B'\:'$B$G$b%@%a!#(B
|
||
+ * $B!&(B magic $B%?%$%W$G!"#8?J?t$O#37eJ,#0!A#7$rD4$Y!"#1#6?J?t$O(B
|
||
+ * isxdigit $B$,??$rJV$94VCf=hM}$5$l$k!#$7$+$7!"#1#b#y#t#e$H(B
|
||
+ * $B$7$F$7$+I>2A$5$l$J$$!#(B
|
||
+ * $B!&%W%j%W%m%;%C%5$r;H$&$H$-$O!"%3%a%s%H$N=q$-J}$KCm0U$7$J$1$l$P$J(B
|
||
+ * $B$i$J$$!#%W%j%W%m%;%C%5$K$h$C$F$O%3%a%s%H$,%(%i!<$K$J$k!#(B
|
||
+ * $B!&%Q%$%W$X$NF~=PNO$N%U%)!<%^%C%H$N<oN`$,(B PNM $B$N$_(B
|
||
+ * $BF~NO(B
|
||
+ * $B%U%!%$%k%]%$%s%?$r(B seek $B$7$F$O$$$1$J$$(B
|
||
+ * $B%U%!%$%k%5%$%:$rMQ$$$F$O$$$1$J$$(B
|
||
+ * $B=PNO(B
|
||
+ * $B%U%!%$%k%]%$%s%?$r(B seek $B$7$F$O$$$1$J$$(B
|
||
+ * exec $B$G$-$J$/$F=*N;$7$?%W%m%;%9$K=q$-9~$_IT2D(B
|
||
+ * $B!&%5%U%#%C%/%9$H%^%8%C%/%J%s%P!<$N;H$$J,$1$r$I$&$9$k$+!#(B
|
||
+ * $B%^%8%C%/%J%s%P!<$,F1$8$G!"%5%U%#%C%/%9$,0[$J$k>l9g$rG'$a$k$+!)(B
|
||
+ * $B!&(Bcompress(gzip)$B$N%U%!%$%k$O%F%s%]%i%j$G$O(B xvtmp??? $B$H$$$&L>A0$J(B
|
||
+ * $B$N$G(B suffix $B$G$O<1JL$G$-$J$$!#(B
|
||
+ *
|
||
+ * $BG'<1$9$k;~$K(B MACBINARY $B$K$OIi$1$k(B(in xv.c)$B!#(B
|
||
+ *
|
||
+ * $BB?=E$K(B pipe $B$rDL$9$3$H$,$G$-$J$$!#(B(pipe $B$,(B seek $B$G$-$J$$$+$i(B)
|
||
+ * $B!&(Bsocketpair $B$G!"(Brecv $B$K(B MSG_PEEK $B%U%i%0$r$D$+$C$F6uFI$_$9$k!#(B
|
||
+ * $B!&$3$l$r$d$k$H%U%!%$%k$NG'<1$,$a$A$c$a$A$cCY$/$J$k!#(B
|
||
+ *
|
||
+ * $B%j%=!<%9$G@_Dj(B
|
||
+ * $B!&%j%=!<%9$G@_Dj$9$kJ}$,LLE]$/$5$$(B
|
||
+ *
|
||
+ * $B%^%8%C%/%J%s%P!<$N@_Dj$K@55,I=8=(B
|
||
+ *
|
||
+ * $B%;!<%VMQ%W%m%;%9$,<:GT$9$k>l9g$NBP:v$,:#0l$D(B
|
||
+ *
|
||
+ * DEC OSF/1 V3.0 $B$G$O!"%Q%$%W$K%G!<%?$,$^$@$J$$;~$KFI$_9~$b$&$H$9$k$H!"(B
|
||
+ * read $B$,IT40A4$K$J$k!#(B(in xvpbm.c)
|
||
+ * $BF1MM$K=q$-9~$_;~$K$bLdBj$,@8$8$k$+$b$7$l$J$$!#(B
|
||
+ */
|
||
+
|
||
+#define NEEDSDIR /* for stat() */
|
||
+#include "xv.h"
|
||
+
|
||
+
|
||
+#ifdef HAVE_MGCSFX
|
||
+
|
||
+
|
||
+#ifdef __osf__
|
||
+# ifdef __alpha
|
||
+# define ARCHITECTURE64 1
|
||
+# endif /* __alpha */
|
||
+#endif /* __osf__ */
|
||
+
|
||
+#ifdef ARCHITECTURE64
|
||
+typedef short int16;
|
||
+typedef int int32;
|
||
+typedef long int64;
|
||
+#else
|
||
+typedef short int16;
|
||
+typedef long int32;
|
||
+#endif /* ARCHITECTURE64 */
|
||
+
|
||
+#ifdef sgi
|
||
+# define vfork fork
|
||
+#endif
|
||
+
|
||
+#define USE_SIGCHLD
|
||
+#if 0
|
||
+# undef USE_SIGCHLD
|
||
+#endif
|
||
+
|
||
+#ifdef USE_SIGCHLD
|
||
+# include <sys/wait.h>
|
||
+#endif
|
||
+
|
||
+typedef struct _mgcsfxtab
|
||
+{
|
||
+ struct _mgcsfxtab *next;
|
||
+ char *description;
|
||
+ int mgcsfx_type;
|
||
+ int offset;
|
||
+ union{
|
||
+ int16 int16_data;
|
||
+ int32 int32_data;
|
||
+ char *string_data;
|
||
+ } dt;
|
||
+ int string_len;
|
||
+ char *suffix;
|
||
+ int input_image_type;
|
||
+ char *input_command;
|
||
+ int output_image_type;
|
||
+ char *output_command;
|
||
+} mgcsfxtab;
|
||
+
|
||
+
|
||
+#ifndef MGCSFXDIR
|
||
+# define MGCSFXDIR "/usr/local/lib"
|
||
+#endif
|
||
+#ifndef SYSCONFDIR
|
||
+# define SYSCONFDIR MGCSFXDIR
|
||
+#endif
|
||
+#ifndef MGCSFX_SITE_RC
|
||
+# define MGCSFX_SITE_RC "xv_mgcsfx"
|
||
+#endif
|
||
+#ifndef MGCSFX_RC
|
||
+# define MGCSFX_RC ".xv_mgcsfx"
|
||
+#endif
|
||
+
|
||
+#ifdef USE_MGCSFX_PREPROCESSOR
|
||
+# ifndef MGCSFX_PREPROCESSOR
|
||
+# define MGCSFX_PREPROCESSOR "/usr/lib/cpp"
|
||
+# endif
|
||
+#endif
|
||
+
|
||
+
|
||
+/* Check type for Magic number and Suffix */
|
||
+enum {T_UNKNOWN,
|
||
+ T_MAGIC, T_SUFFIX,
|
||
+ T_BEINT16, T_BEINT32, T_BEINT64,
|
||
+ T_LEINT16, T_LEINT32, T_LEINT64};
|
||
+
|
||
+/* Image Type for input and output format */
|
||
+enum {IT_UNKNOWN,
|
||
+#ifdef HAVE_MGCSFX_AUTO
|
||
+ IT_AUTO,
|
||
+#endif /* HAVE_MGCSFX_AUTO */
|
||
+ IT_PNM, IT_PPM, IT_PGM, IT_PBM,
|
||
+ IT_PNM_RAW, IT_PPM_RAW, IT_PGM_RAW, IT_PBM_RAW,
|
||
+ IT_PNM_ASCII, IT_PPM_ASCII, IT_PGM_ASCII, IT_PBM_ASCII,
|
||
+ IT_GIF, IT_JPEG, IT_TIFF, IT_JFIF, /* IT_PS, IT_COMPRESS,*/
|
||
+ IT_XBM, IT_XPM, IT_BMP, IT_SUNRAS, IT_IRIS, IT_XWD,
|
||
+ /* IT_TARGA, IT_FITS, IT_PM, IT_UTAHRLE, IT_PCX, IT_PDSVICAR, IT_IFF, */
|
||
+ IT_MAG, IT_MAKI, IT_PI, IT_PIC, IT_PIC2 /* , IT_PCD */};
|
||
+
|
||
+
|
||
+/*--------------------------------------------------------------------------*/
|
||
+void mgcsfx_handler PARM((int));
|
||
+void mgcsfx_handler_setup PARM((void));
|
||
+
|
||
+#ifdef USE_MGCSFX_PREPROCESSOR
|
||
+static char *get_tmp_fname PARM((void));
|
||
+static char *make_preprocessed_file PARM((char *));
|
||
+#endif /* USE_MGCSFX_PREPROCESSOR */
|
||
+
|
||
+int is_mgcsfx PARM((char *, unsigned char *, int));
|
||
+
|
||
+char *mgcsfx_auto_input_com PARM((char *));
|
||
+
|
||
+
|
||
+static mgcsfxtab *free_mgcsfx PARM((mgcsfxtab *));
|
||
+static char *fgettoken PARM((FILE*, int));
|
||
+static int string_fin PARM((char *));
|
||
+static int type_mgcsfx PARM((char *));
|
||
+static int type_image PARM((char *));
|
||
+
|
||
+static void read_mgcsfx PARM((mgcsfxtab **, char *));
|
||
+static void init_mgcsfx PARM((void));
|
||
+static mgcsfxtab *find_mgcsfx PARM((char *, unsigned char *, int));
|
||
+
|
||
+int LoadMGCSFX PARM((char *, PICINFO *));
|
||
+
|
||
+#ifdef SVR4
|
||
+typedef void Sigfunc(int);
|
||
+static Sigfunc *xv_signal PARM((int , Sigfunc *));
|
||
+#endif
|
||
+
|
||
+/*--------------------------------------------------------------------------*/
|
||
+mgcsfxtab *mgcsfx_table = NULL;
|
||
+int mgcsfx_setup_flag = 0;
|
||
+
|
||
+int nitem_mgcsfx = 0;
|
||
+int desc_width = 0;
|
||
+
|
||
+int max_offset_mgcsfx = 0;
|
||
+int max_length_mgcsfx = 0;
|
||
+int need_buf_size = 0;
|
||
+
|
||
+static char input_command_ex[1024];
|
||
+static int input_command_ex_flag = 0;
|
||
+
|
||
+#ifdef USE_SIGCHLD
|
||
+static int w_p_fail=0;
|
||
+#endif
|
||
+
|
||
+/*--------------------------------------------------------------------------*/
|
||
+
|
||
+/***************************************************/
|
||
+void mgcsfx_handler(sig)
|
||
+ int sig;
|
||
+{
|
||
+#ifdef USE_SIGCHLD
|
||
+ int pid, pst;
|
||
+#endif
|
||
+
|
||
+#if defined(SYSV) || defined(SVR4)
|
||
+ sighold(sig);
|
||
+#else
|
||
+ sigblock(sigmask(sig));
|
||
+#endif
|
||
+
|
||
+#ifdef USE_SIGCHLD
|
||
+ if(w_p_fail == 1){
|
||
+ /*
|
||
+ * At this point, process write to broken pipe.
|
||
+ * Probably external command was can't exec.
|
||
+ */
|
||
+ w_p_fail = 2;
|
||
+ pid = wait(&pst);
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ return;
|
||
+
|
||
+ /* Quit(1); */ /*exit(1);*/
|
||
+}
|
||
+
|
||
+void mgcsfx_handler_setup()
|
||
+{
|
||
+#ifdef SVR4
|
||
+ xv_signal(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler);
|
||
+ xv_signal(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler);
|
||
+#else
|
||
+# ifdef SYSV
|
||
+ sigset(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler);
|
||
+ sigset(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler);
|
||
+# else
|
||
+ signal(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler);
|
||
+ signal(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler);
|
||
+# endif
|
||
+#endif
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+#ifdef USE_MGCSFX_PREPROCESSOR
|
||
+static char *get_tmp_fname()
|
||
+{
|
||
+ static char tmp[MAXPATHLEN+1];
|
||
+
|
||
+#ifndef VMS
|
||
+ sprintf(tmp, "%s/xvmgcsfxXXXXXX",tmpdir);
|
||
+#else
|
||
+ /* sprintf(tmp, "Sys$Scratch:xvmgcsfxXXXXXX"); */
|
||
+ strcpy(tmp, "[]xvmgcsfxXXXXXX");
|
||
+#endif /* VMS */
|
||
+
|
||
+#ifdef USE_MKSTEMP
|
||
+ close(mkstemp(tmp));
|
||
+#else
|
||
+ mktemp(tmp);
|
||
+#endif
|
||
+
|
||
+ return tmp;
|
||
+}
|
||
+
|
||
+static char *make_preprocessed_file(fname)
|
||
+ char *fname;
|
||
+{
|
||
+ char buf[512];
|
||
+ char *tmp_name;
|
||
+
|
||
+ tmp_name = get_tmp_fname();
|
||
+
|
||
+#ifndef VMS
|
||
+ sprintf(buf,"%s %s > %s", MGCSFX_PREPROCESSOR, fname, tmp_name);
|
||
+#else
|
||
+ sprintf(buf,"%s %s > %s", MGCSFX_PREPROCESSOR, fname, tmp_name); /* really OK? */
|
||
+#endif
|
||
+
|
||
+ SetISTR(ISTR_INFO, "Preprocessing '%s'...", BaseName(fname));
|
||
+#ifndef VMS
|
||
+ if (system(buf))
|
||
+#else
|
||
+ if (!system(buf))
|
||
+#endif
|
||
+ {
|
||
+ SetISTR(ISTR_INFO, "Unable to preprocess '%s'.", BaseName(fname));
|
||
+ Warning();
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ return tmp_name;
|
||
+}
|
||
+#endif /* USE_MGCSFX_PREPROCESSOR */
|
||
+
|
||
+/***************************************************/
|
||
+/* $BG'<1$G$-$k%U%!%$%k$+$I$&$+D4$Y$k(B */
|
||
+int is_mgcsfx(fname,buffer,size)
|
||
+ char *fname;
|
||
+ unsigned char *buffer;
|
||
+ int size;
|
||
+{
|
||
+ mgcsfxtab *magic;
|
||
+ FILE *fp;
|
||
+ unsigned char *buf;
|
||
+ int s;
|
||
+
|
||
+ if(nomgcsfx){
|
||
+ return 0;
|
||
+ }else{
|
||
+ if(size < need_buf_size){
|
||
+ if((buf = (unsigned char *)calloc(need_buf_size, sizeof(char)))==NULL){
|
||
+ fprintf(stderr,"Can't allocate memory\n");
|
||
+ return 0;
|
||
+ }
|
||
+ if((fp = xv_fopen(fname, "r"))==NULL){
|
||
+ fprintf(stderr,"Can't open file %s\n", fname);
|
||
+ free(buf);
|
||
+ return 0;
|
||
+ }
|
||
+ s = fread(buf, 1, need_buf_size, fp);
|
||
+ if((magic = find_mgcsfx(fname, buf, s))!=NULL &&
|
||
+ magic->input_command != NULL){
|
||
+ free(buf);
|
||
+ fclose(fp);
|
||
+ return 1;
|
||
+ }else{
|
||
+ free(buf);
|
||
+ fclose(fp);
|
||
+ return 0;
|
||
+ }
|
||
+ }else{
|
||
+ if((magic = find_mgcsfx(fname, buffer, size))!=NULL &&
|
||
+ magic->input_command != NULL){
|
||
+ return 1;
|
||
+ }else{
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+#ifdef HAVE_MGCSFX_AUTO
|
||
+char *mgcsfx_auto_input_com(fname)
|
||
+char *fname;
|
||
+{
|
||
+ static char command[1024];
|
||
+ mgcsfxtab *magic;
|
||
+ char *ptr;
|
||
+
|
||
+ FILE *fp;
|
||
+ unsigned char *buf;
|
||
+ int s;
|
||
+
|
||
+ if((buf = (unsigned char *)calloc(need_buf_size, sizeof(char)))==NULL){
|
||
+ fprintf(stderr,"Can't allocate memory\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ if((fp = xv_fopen(fname, "r"))==NULL){
|
||
+ fprintf(stderr,"Can't open file %s\n", fname);
|
||
+ free(buf);
|
||
+ return NULL;
|
||
+ }
|
||
+ s = fread(buf, 1, need_buf_size, fp);
|
||
+ if((magic = find_mgcsfx(fname, buf, s))!=NULL &&
|
||
+ magic->input_command != NULL && magic->input_image_type == IT_AUTO){
|
||
+ if ((ptr = strstr(magic->input_command, "%s"))){
|
||
+ sprintf(command, magic->input_command, fname);
|
||
+ }else{
|
||
+ sprintf(command, "%s < %s", magic->input_command, fname);
|
||
+ }
|
||
+ free(buf);
|
||
+ fclose(fp);
|
||
+ return command;
|
||
+ }else{
|
||
+ free(buf);
|
||
+ fclose(fp);
|
||
+ return NULL;
|
||
+ }
|
||
+}
|
||
+#endif /* HAVE_MGCSFX_AUTO */
|
||
+
|
||
+/***************************************************/
|
||
+static mgcsfxtab *free_mgcsfx(m)
|
||
+ mgcsfxtab *m;
|
||
+{
|
||
+ mgcsfxtab *next;
|
||
+ if(m == NULL) return NULL;
|
||
+ next = m->next;
|
||
+ if(m->description != NULL) free(m->description);
|
||
+ if(m->mgcsfx_type == T_MAGIC && m->dt.string_data != NULL)
|
||
+ free(m->dt.string_data);
|
||
+ if(m->suffix != NULL) free(m->suffix);
|
||
+ if(m->input_command != NULL) free(m->input_command);
|
||
+ if(m->output_command != NULL) free(m->output_command);
|
||
+ free(m);
|
||
+ return next;
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+/* char c $B$^$?$O(B '\n' $B$G6h@Z$i$l$?J8;zNs$r<h$j=P$9(B
|
||
+ * $B%U%!%$%k$N:G8e$^$GFI$s$@$i(B NULL $B$rJV$9(B
|
||
+ * $B2~9T$J$i2~9T$rJV$9(B($B2~9T$G6h@Z$i$l$?>l9g$O(B '\n' $B$r%9%H%j!<%`$KLa$9(B)
|
||
+ */
|
||
+#define CBUF_SIZE 1024
|
||
+static char *fgettoken(fp, c)
|
||
+ FILE *fp;
|
||
+ int c; /* Real mean is char */
|
||
+{
|
||
+ char *buf;
|
||
+ char *buf2;
|
||
+ int i;
|
||
+ int n=0;
|
||
+ int max=0;
|
||
+ int count = 1;
|
||
+
|
||
+ char *ss;
|
||
+ char *se;
|
||
+
|
||
+ if((buf = (char *)calloc(CBUF_SIZE, sizeof(char))) == NULL){
|
||
+ fprintf(stderr,"Can't allocate memory\n");
|
||
+ exit(1);
|
||
+ }
|
||
+ max = CBUF_SIZE;
|
||
+ count = 2;
|
||
+
|
||
+ do{
|
||
+ if((i = getc(fp))==EOF || i == '\n' || i == c) break;
|
||
+
|
||
+ buf[n] = (char)i;
|
||
+
|
||
+ if(i != c && n == max-1){
|
||
+ buf[max] = '\0';
|
||
+ if((buf2 = (char *)calloc(CBUF_SIZE * count, sizeof(char))) == NULL){
|
||
+ fprintf(stderr,"Can't allocate memory\n");
|
||
+ exit(1);
|
||
+ }
|
||
+ strcpy(buf2, buf);
|
||
+ free(buf);
|
||
+ buf = buf2;
|
||
+ buf2 = NULL;
|
||
+ max = CBUF_SIZE * count;
|
||
+ count++;
|
||
+ }
|
||
+
|
||
+ n++;
|
||
+ }while(i != c);
|
||
+
|
||
+ buf[n] = '\0';
|
||
+
|
||
+ /* $B:G=i$H:G8e$N6uGrJ8;z$r@Z$j5M$a$k(B */
|
||
+ ss = buf + strspn(buf, " \t\b\r\n"); /* find the first non-white space */
|
||
+ se = buf + strlen(buf); /* find the end of the string */
|
||
+
|
||
+ /* strip from the end first */
|
||
+ while ((--se >= ss) && strchr(" \t\b\r\n", *se));
|
||
+ *(++se) = '\0';
|
||
+
|
||
+ if(i == EOF && strlen(ss)==0){ /* EOF $B$J$i(B NULL $B$rJV$9(B */
|
||
+ free(buf);
|
||
+ return NULL;
|
||
+ }else if(i == '\n' && strlen(ss)==0){ /* $B2~9T$N$_$N>l9g(B */
|
||
+ static char cr[2] = {'\n','\0'};
|
||
+ buf2 = strdup(cr);
|
||
+ free(buf);
|
||
+ return buf2;
|
||
+ }else{ /* $BDL>o(B */
|
||
+ if(i == '\n' && strlen(ss)>0) ungetc(i,fp);
|
||
+ buf2 = strdup(ss);
|
||
+ free(buf);
|
||
+ return buf2;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+/* $BJ8;zNsCf$NFC<l5-9f(B(\)$B$r@5$7$$$b$N$K$9$k(B
|
||
+ */
|
||
+static int string_fin(string_data)
|
||
+ char *string_data;
|
||
+{
|
||
+ char *cptr;
|
||
+ char *ptr;
|
||
+ int length;
|
||
+
|
||
+ /* Change all the \xx sequences into a single character */
|
||
+ cptr = string_data;
|
||
+
|
||
+ for (ptr = cptr; *ptr; ++ptr){
|
||
+ if (*ptr != '\\'){
|
||
+ *cptr = *ptr;
|
||
+ }else{
|
||
+ switch (*(++ptr)){
|
||
+#if defined(__STDC__)
|
||
+ case 'a': /* Audible alert (terminal bell) */
|
||
+ *cptr = '\007';
|
||
+ break;
|
||
+ case '?': /* Question mark */
|
||
+ *cptr = '\?';
|
||
+ break;
|
||
+#endif
|
||
+ case 'b': /* Backspace */
|
||
+ *cptr = '\b';
|
||
+ break;
|
||
+ case 'f': /* Form feed */
|
||
+ *cptr = '\f';
|
||
+ break;
|
||
+ case 'n': /* Line feed */
|
||
+ *cptr = '\n';
|
||
+ break;
|
||
+ case 'r': /* Carriage return */
|
||
+ *cptr = '\r';
|
||
+ break;
|
||
+ case 't': /* Horizontal tab */
|
||
+ *cptr = '\t';
|
||
+ break;
|
||
+ case 'v': /* Vertical tab */
|
||
+ *cptr = '\v';
|
||
+ break;
|
||
+ case '\\': /* Backslash */
|
||
+ *cptr = '\\';
|
||
+ break;
|
||
+ case '\'': /* Single quote */
|
||
+ *cptr = '\'';
|
||
+ break;
|
||
+ case '"': /* Double quote */
|
||
+ *cptr = '\"';
|
||
+ break;
|
||
+ case '0': /* Octal constant \0 ... \377 */
|
||
+ case '1':
|
||
+ case '2':
|
||
+ case '3':
|
||
+ case '4':
|
||
+ case '5':
|
||
+ case '6':
|
||
+ case '7':
|
||
+ if ((ptr[1] >= '0') && (ptr[1] <= '7')){
|
||
+ if ((ptr[2] >= '0') && (ptr[2] <= '7')){ /* \000 ...\377 */
|
||
+ *cptr = ((*ptr - '0') * 64) +((ptr[1] - '0') * 8) +(ptr[1] - '0');
|
||
+ ptr += 2;
|
||
+ }else{ /* \00 ...\77 */
|
||
+ *cptr = ((*ptr - '0') * 8) + (ptr[1] - '0');
|
||
+ ++ptr;
|
||
+ }
|
||
+ }else{ /* \0 ...\7 */
|
||
+ *cptr = *ptr - '0';
|
||
+ }
|
||
+ break;
|
||
+ case 'x': /* Hexadecimal constant \x0 .. \xff */
|
||
+ if (isxdigit (ptr[1])){
|
||
+ *cptr = 0;
|
||
+ while (isxdigit (*(++ptr)))
|
||
+ *cptr = (*cptr * 16) +
|
||
+ (*ptr > '9' ? tolower (*ptr) - ('a' - 10) : *ptr - '0');
|
||
+ --ptr;
|
||
+ break;
|
||
+ }
|
||
+ default:
|
||
+ /* *(cptr++) = '\\'; No use for treat '\z' as 'z' */
|
||
+ *cptr = *ptr;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ ++cptr;
|
||
+ }
|
||
+ *cptr = '\0';
|
||
+ length = cptr - string_data;
|
||
+ return length;
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+static int type_mgcsfx(str)
|
||
+ char *str;
|
||
+{
|
||
+ if(str == NULL){
|
||
+ return T_UNKNOWN;
|
||
+ }else if(!strcmp(str, "magic") || !strcmp(str, "MAGIC")){
|
||
+ return T_MAGIC;
|
||
+ }else if(!strcmp(str, "string") || !strcmp(str, "STRING")){
|
||
+ return T_MAGIC;
|
||
+ }else if(!strcmp(str, "suffix") || !strcmp(str, "SUFFIX")){
|
||
+ return T_SUFFIX;
|
||
+ }else if(!strcmp(str, "beint16") || !strcmp(str, "BEINT16")){
|
||
+ return T_BEINT16;
|
||
+ }else if(!strcmp(str, "leint16") || !strcmp(str, "LEINT16")){
|
||
+ return T_LEINT16;
|
||
+ }else if(!strcmp(str, "beint32") || !strcmp(str, "BEINT32")){
|
||
+ return T_BEINT32;
|
||
+ }else if(!strcmp(str, "leint32") || !strcmp(str, "LEINT32")){
|
||
+ return T_LEINT32;
|
||
+ }else{
|
||
+ return T_UNKNOWN;
|
||
+ }
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+static int type_image(str)
|
||
+ char *str;
|
||
+{
|
||
+ if(str == NULL){
|
||
+ return IT_UNKNOWN;
|
||
+#ifdef HAVE_MGCSFX_AUTO
|
||
+ }else if(!strcmp(str, "auto") || !strcmp(str, "AUTO")){
|
||
+ return IT_AUTO;
|
||
+#endif /* HAVE_MGCSFX_AUTO */
|
||
+ }else if(!strcmp(str, "pnm") || !strcmp(str, "PNM")){
|
||
+ return IT_PNM;
|
||
+ }else if(!strcmp(str, "ppm") || !strcmp(str, "PPM")){
|
||
+ return IT_PPM;
|
||
+ }else if(!strcmp(str, "pgm") || !strcmp(str, "PGM")){
|
||
+ return IT_PGM;
|
||
+ }else if(!strcmp(str, "pbm") || !strcmp(str, "PBM")){
|
||
+ return IT_PBM;
|
||
+ }else if(!strcmp(str, "pnm_raw") || !strcmp(str, "PNM_RAW")){
|
||
+ return IT_PNM_RAW;
|
||
+ }else if(!strcmp(str, "ppm_raw") || !strcmp(str, "PPM_RAW")){
|
||
+ return IT_PPM_RAW;
|
||
+ }else if(!strcmp(str, "pgm_raw") || !strcmp(str, "PGM_RAW")){
|
||
+ return IT_PGM_RAW;
|
||
+ }else if(!strcmp(str, "pbm_raw") || !strcmp(str, "PBM_RAW")){
|
||
+ return IT_PBM_RAW;
|
||
+ }else if(!strcmp(str, "pnm_ascii") || !strcmp(str, "PNM_ASCII")){
|
||
+ return IT_PNM_ASCII;
|
||
+ }else if(!strcmp(str, "ppm_ascii") || !strcmp(str, "PPM_ASCII")){
|
||
+ return IT_PPM_ASCII;
|
||
+ }else if(!strcmp(str, "pgm_ascii") || !strcmp(str, "PGM_ASCII")){
|
||
+ return IT_PGM_ASCII;
|
||
+ }else if(!strcmp(str, "pbm_ascii") || !strcmp(str, "PBM_ASCII")){
|
||
+ return IT_PBM_ASCII;
|
||
+
|
||
+ }else if(!strcmp(str, "gif") || !strcmp(str, "GIF")){
|
||
+ return IT_GIF;
|
||
+ }else if(!strcmp(str, "jpeg") || !strcmp(str, "JPEG")){
|
||
+ return IT_JPEG;
|
||
+ }else if(!strcmp(str, "tiff") || !strcmp(str, "TIFF")){
|
||
+ return IT_TIFF;
|
||
+ }else if(!strcmp(str, "jfif") || !strcmp(str, "JFIF")){
|
||
+ return IT_JFIF;
|
||
+
|
||
+ }else if(!strcmp(str, "xbm") || !strcmp(str, "XBM")){
|
||
+ return IT_XBM;
|
||
+ }else if(!strcmp(str, "xpm") || !strcmp(str, "XPM")){
|
||
+ return IT_XPM;
|
||
+ }else if(!strcmp(str, "bmp") || !strcmp(str, "BMP")){
|
||
+ return IT_BMP;
|
||
+ }else if(!strcmp(str, "sunras") || !strcmp(str, "SUNRAS")){
|
||
+ return IT_SUNRAS;
|
||
+ }else if(!strcmp(str, "iris") || !strcmp(str, "IRIS")){
|
||
+ return IT_IRIS;
|
||
+ }else if(!strcmp(str, "xwd") || !strcmp(str, "XWD")){
|
||
+ return IT_XWD;
|
||
+
|
||
+ }else if(!strcmp(str, "mag") || !strcmp(str, "MAG")){
|
||
+ return IT_MAG;
|
||
+ }else if(!strcmp(str, "maki") || !strcmp(str, "MAKI")){
|
||
+ return IT_MAKI;
|
||
+ }else if(!strcmp(str, "pi") || !strcmp(str, "PI")){
|
||
+ return IT_PI;
|
||
+ }else if(!strcmp(str, "pic") || !strcmp(str, "PIC")){
|
||
+ return IT_PIC;
|
||
+ }else if(!strcmp(str, "pic2") || !strcmp(str, "PIC2")){
|
||
+ return IT_PIC2;
|
||
+
|
||
+ }else{
|
||
+ return IT_UNKNOWN;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*--------------------------------------------------------------------------*/
|
||
+#define mgcsfx_read_error(FILENAME, LINENUM, AFTERFIELD) \
|
||
+fprintf (stderr,\
|
||
+"%s: line %d: missing fields of %s field\n",\
|
||
+FILENAME, LINENUM, AFTERFIELD);
|
||
+
|
||
+#define magic_type_error(FILENAME, LINENUM, MAGICNUMBER) \
|
||
+fprintf (stderr,\
|
||
+"%s: line %d: invalid <magic type> field '%s'\n",\
|
||
+FILENAME, LINENUM, MAGICNUMBER);
|
||
+/*--------------------------------------------------------------------------*/
|
||
+
|
||
+/***************************************************/
|
||
+static void read_mgcsfx(mgcsfx_table, fname)
|
||
+ mgcsfxtab **mgcsfx_table;
|
||
+ char *fname;
|
||
+{
|
||
+ FILE *fp;
|
||
+ char *s;
|
||
+ int line_number = 0;
|
||
+ int str_len;
|
||
+ int reach_end;
|
||
+ int def_err;
|
||
+
|
||
+ char *description;
|
||
+ char *mgcsfx_type;
|
||
+ char *offset;
|
||
+ char *magic;
|
||
+ char *suffix;
|
||
+ char *i_img;
|
||
+ char *i_com;
|
||
+ char *o_img;
|
||
+ char *o_com;
|
||
+
|
||
+ mgcsfxtab *ent;
|
||
+ mgcsfxtab **entry;
|
||
+
|
||
+
|
||
+ if((fp=fopen(fname, "r"))==NULL){
|
||
+ /* fprintf(stderr, "Can't open %s\n",fname); */
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ while(1){
|
||
+retry:
|
||
+ line_number++;
|
||
+ def_err = 0;
|
||
+
|
||
+ s= NULL;
|
||
+ description = mgcsfx_type = offset = magic = suffix
|
||
+ = i_img = i_com = o_img = o_com = NULL;
|
||
+ reach_end = 0;
|
||
+
|
||
+ if((s = fgettoken(fp, ':'))==NULL) break; /* EOF $B$J$i=*$j(B */
|
||
+ if(*s == '#'){/* $B@hF,$,(B '#' $B$J$iFI$_$H$P$9(B */
|
||
+ while((s = fgettoken(fp, '\n'))!=NULL){
|
||
+ if(*s == '\n'){
|
||
+ free(s);
|
||
+ goto retry;
|
||
+ }
|
||
+ free(s);
|
||
+ }
|
||
+ if(s == NULL) break;
|
||
+ }else if(*s == '\n'){/* $B6u9T$OL5;k(B */
|
||
+ free(s);
|
||
+ goto retry;
|
||
+ }
|
||
+ if(strlen(s) > 0) description = s;
|
||
+ else free(s);
|
||
+
|
||
+ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */
|
||
+ if(s != NULL) free(s);
|
||
+ mgcsfx_read_error(fname, line_number, "data type");
|
||
+ goto next;
|
||
+ }
|
||
+ if(strlen(s) > 0) mgcsfx_type = s;
|
||
+ else free(s);
|
||
+
|
||
+ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */
|
||
+ if(s != NULL) free(s);
|
||
+ mgcsfx_read_error(fname, line_number, "byte offset");
|
||
+ goto next;
|
||
+ }
|
||
+ if(strlen(s) > 0) offset = s;
|
||
+ else free(s);
|
||
+
|
||
+ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */
|
||
+ if(s != NULL) free(s);
|
||
+ mgcsfx_read_error(fname, line_number, "magic number");
|
||
+ goto next;
|
||
+ }
|
||
+ if(strlen(s) > 0) magic = s;
|
||
+ else free(s);
|
||
+
|
||
+ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */
|
||
+ if(s != NULL) free(s);
|
||
+ mgcsfx_read_error(fname, line_number, "suffix");
|
||
+ goto next;
|
||
+ }
|
||
+ if(strlen(s) > 0) suffix = s;
|
||
+ else free(s);
|
||
+
|
||
+ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */
|
||
+ if(s != NULL) free(s);
|
||
+ mgcsfx_read_error(fname, line_number, "input image type");
|
||
+ goto next;
|
||
+ }
|
||
+ if(strlen(s) > 0) i_img = s;
|
||
+ else free(s);
|
||
+
|
||
+ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */
|
||
+ if(s != NULL) free(s);
|
||
+ mgcsfx_read_error(fname, line_number, "input command");
|
||
+ goto next;
|
||
+ }
|
||
+ if(strlen(s) > 0) i_com = s;
|
||
+ else free(s);
|
||
+
|
||
+ if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */
|
||
+ if(s != NULL) free(s);
|
||
+ mgcsfx_read_error(fname, line_number, "output image type");
|
||
+ goto next;
|
||
+ }
|
||
+ if(strlen(s) > 0) o_img = s;
|
||
+ else free(s);
|
||
+
|
||
+ if((s = fgettoken(fp, '#'))==NULL || *s == '\n'){/* $B2?$b$J$$$J$i@_Dj%_%9(B */
|
||
+ /*
|
||
+ free(s);
|
||
+ mgcsfx_read_error(fname, line_number, "output command");
|
||
+ goto next;
|
||
+ */
|
||
+ if(s != NULL){
|
||
+ *s = '\0';
|
||
+ reach_end = 1;
|
||
+ }
|
||
+ }
|
||
+ if(s != NULL){
|
||
+ if(strlen(s) > 0) o_com = s;
|
||
+ else free(s);
|
||
+ }
|
||
+
|
||
+ if(reach_end == 0){
|
||
+ while((s = fgettoken(fp, '\n'))!=NULL){/* $B9TKv$N%4%_$r<N$F$k(B */
|
||
+ if(*s == '\n'){
|
||
+ free(s);
|
||
+ break; /* goto next; */
|
||
+ }
|
||
+ free(s);
|
||
+ }
|
||
+ }else{
|
||
+ reach_end = 0;
|
||
+ }
|
||
+
|
||
+
|
||
+
|
||
+ /* --------------------------------------------------------------------- */
|
||
+next:;
|
||
+
|
||
+ if(DEBUG){
|
||
+ fprintf(stderr,"Read: file %s: line %d.\n", fname, line_number);
|
||
+ fprintf(stderr,"Description : %s\n",
|
||
+ description ? description : "-- error --");
|
||
+ fprintf(stderr,"Type : %s\n",
|
||
+ mgcsfx_type ? mgcsfx_type : "-- error --");
|
||
+ fprintf(stderr,"Offset : %s\n", offset ? offset : "--+--");
|
||
+ fprintf(stderr,"Magic : %s\n", magic ? magic : "--+--");
|
||
+ fprintf(stderr,"Suffix : %s\n", suffix ? suffix : "--+--");
|
||
+ fprintf(stderr,"i Image : %s\n", i_img ? i_img : "--+--");
|
||
+ fprintf(stderr,"i Command : %s\n", i_com ? i_com : "--+--");
|
||
+ fprintf(stderr,"o Image : %s\n", o_img ? o_img : "--+--");
|
||
+ fprintf(stderr,"o Command : %s\n", o_com ? o_com : "--+--");
|
||
+ fprintf(stderr,"\n");
|
||
+ }
|
||
+
|
||
+ /* create mgcsfxtab */
|
||
+ if((ent = (mgcsfxtab *) malloc (sizeof (mgcsfxtab)))==NULL){
|
||
+ fprintf(stderr,"Can't allocate memory\n");
|
||
+ exit(1);
|
||
+ }
|
||
+ ent->next = NULL;
|
||
+ ent->description = NULL;
|
||
+ ent->mgcsfx_type = T_UNKNOWN;
|
||
+ ent->offset = 0;
|
||
+ ent->string_len = 0;
|
||
+ ent->suffix = NULL;
|
||
+ ent->input_image_type = IT_UNKNOWN;
|
||
+ ent->input_command = NULL;
|
||
+ ent->output_image_type = IT_UNKNOWN;
|
||
+ ent->output_command = NULL;
|
||
+
|
||
+ if(description != NULL){
|
||
+ ent->description = description;
|
||
+ description = NULL;
|
||
+ }else{
|
||
+ fprintf (stderr,"%s: line %d: undefined <description> field.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+
|
||
+ if(mgcsfx_type == NULL){
|
||
+ fprintf (stderr,"%s: line %d: undefined <mgcsfx type> field.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ ent->mgcsfx_type = type_mgcsfx(mgcsfx_type);
|
||
+ switch(ent->mgcsfx_type){
|
||
+ case T_SUFFIX:
|
||
+ if(suffix == NULL){
|
||
+ fprintf (stderr,
|
||
+ "%s: line %d: conflict definition : undefined <suffix> field.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ break;
|
||
+ case T_BEINT16:
|
||
+ if (sscanf(magic, "%hi", &(ent->dt.int16_data)) != 1){
|
||
+ magic_type_error(fname, line_number, magic);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ break;
|
||
+ case T_LEINT16:
|
||
+ if (sscanf(magic, "%hi", &(ent->dt.int16_data)) != 1){
|
||
+ magic_type_error(fname, line_number, magic);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ break;
|
||
+#ifdef ARCHITECTURE64
|
||
+ case T_BEINT32:
|
||
+ if (sscanf(magic, "%i", &(ent->dt.int32_data)) != 1){
|
||
+ magic_type_error(fname, line_number, magic);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ break;
|
||
+ case T_LEINT32:
|
||
+ if (sscanf(magic, "%i", &(ent->dt.int32_data)) != 1){
|
||
+ magic_type_error(fname, line_number, magic);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ break;
|
||
+#else
|
||
+ case T_BEINT32:
|
||
+ if (sscanf(magic, "%li", &(ent->dt.int32_data)) != 1){
|
||
+ magic_type_error(fname, line_number, magic);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ break;
|
||
+ case T_LEINT32:
|
||
+ if (sscanf(magic, "%li", &(ent->dt.int32_data)) != 1){
|
||
+ magic_type_error(fname, line_number, magic);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ break;
|
||
+#endif /* ARCHITECTURE64 */
|
||
+ case T_MAGIC:
|
||
+ if(magic == NULL){
|
||
+ fprintf (stderr,"%s: line %d: undefined <magic> field.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ if((str_len = string_fin(magic))<=0){
|
||
+ fprintf (stderr,"%s: line %d: invalid <magic> field.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+
|
||
+ ent->string_len = str_len;
|
||
+ if((ent->dt.string_data = (char *)malloc(str_len + 1))==NULL){
|
||
+ fprintf(stderr,"Can't allocate memory\n");
|
||
+ exit(1);
|
||
+ }
|
||
+ memcpy(ent->dt.string_data, magic, str_len + 1);
|
||
+ break;
|
||
+ case T_UNKNOWN:
|
||
+ default:
|
||
+ fprintf (stderr,"%s: line %d: invalid <mgcsfx type> field.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ break;
|
||
+ };
|
||
+
|
||
+
|
||
+ if(offset == NULL){
|
||
+ if(ent->mgcsfx_type == T_MAGIC ||
|
||
+ ent->mgcsfx_type == T_BEINT16 ||
|
||
+ ent->mgcsfx_type == T_LEINT16 ||
|
||
+ ent->mgcsfx_type == T_BEINT32 ||
|
||
+ ent->mgcsfx_type == T_LEINT32){
|
||
+ fprintf (stderr,
|
||
+ "%s: line %d: conflict definition : undefined <offset> field.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ }else{
|
||
+ if(ent->mgcsfx_type != T_SUFFIX) sscanf(offset, "%i", &(ent->offset));
|
||
+ }
|
||
+
|
||
+ if(suffix != NULL){
|
||
+ ent->suffix = suffix;
|
||
+ suffix = NULL;
|
||
+ }
|
||
+
|
||
+ if((i_img == NULL && i_com == NULL) && (o_img == NULL || o_com == NULL)){
|
||
+ fprintf (stderr,"%s: line %d: invalid definition.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+ if((o_img == NULL && o_com == NULL) && (i_img == NULL || i_com == NULL)){
|
||
+ fprintf (stderr,"%s: line %d: invalid definition.\n",
|
||
+ fname, line_number);
|
||
+ def_err ++;
|
||
+ goto next2;
|
||
+ }
|
||
+
|
||
+ if(i_img != NULL && i_com != NULL){
|
||
+ ent->input_image_type = type_image(i_img);
|
||
+ ent->input_command = i_com;
|
||
+ i_com = NULL;
|
||
+ }else{
|
||
+ ent->input_image_type = IT_UNKNOWN;
|
||
+ ent->input_command = NULL;
|
||
+ }
|
||
+
|
||
+ if(o_img != NULL && o_com != NULL){
|
||
+ ent->output_image_type = type_image(o_img);
|
||
+ ent->output_command = o_com;
|
||
+ o_com = NULL;
|
||
+ }else{
|
||
+ ent->output_image_type = IT_UNKNOWN;
|
||
+ ent->output_command = NULL;
|
||
+ }
|
||
+ /* end of create mgcsfxtab */
|
||
+
|
||
+
|
||
+next2:;
|
||
+
|
||
+ if(def_err != 0 || DEBUG){
|
||
+ fprintf(stderr,"Description : %s \t -> %s\n",
|
||
+ description ? description : "--+--",
|
||
+ ent->description ? ent->description : "-- error --");
|
||
+ fprintf(stderr,"Type : %s \t -> %d\n",
|
||
+ mgcsfx_type ? mgcsfx_type : "--+--",
|
||
+ ent->mgcsfx_type);
|
||
+ fprintf(stderr,"Offset : %s \t -> %d\n",
|
||
+ offset ? offset : "--+--",
|
||
+ ent->offset);
|
||
+
|
||
+ fprintf(stderr,"Magic : %s", magic ? magic : "--+--");
|
||
+ switch(ent->mgcsfx_type){
|
||
+ case T_BEINT16:
|
||
+ case T_LEINT16:
|
||
+ fprintf(stderr," \t -> %d\n",ent->dt.int16_data);
|
||
+ break;
|
||
+ case T_BEINT32:
|
||
+ case T_LEINT32:
|
||
+ fprintf(stderr," \t -> %ld\n",ent->dt.int32_data);
|
||
+ break;
|
||
+ case T_MAGIC:
|
||
+ fprintf(stderr," \t -> %s\n",ent->dt.string_data);
|
||
+ break;
|
||
+ default:
|
||
+ fprintf(stderr,"\n");
|
||
+ break;
|
||
+ };
|
||
+
|
||
+ fprintf(stderr,"Suffix : %s \t -> %s\n",
|
||
+ suffix ? suffix : "--+--",
|
||
+ ent->suffix ? ent->suffix : "--+--");
|
||
+ fprintf(stderr,"i Image : %s \t -> %d\n",
|
||
+ i_img ? i_img : "--+--",
|
||
+ ent->input_image_type);
|
||
+ fprintf(stderr,"i Command : %s \t -> %s\n",
|
||
+ i_com ? i_com : "--+--",
|
||
+ ent->input_command ? ent->input_command : "--+--");
|
||
+ fprintf(stderr,"o Image : %s \t -> %d\n",
|
||
+ o_img ? o_img : "--+--",
|
||
+ ent->output_image_type);
|
||
+ fprintf(stderr,"o Command : %s \t -> %s\n",
|
||
+ o_com ? o_com : "--+--",
|
||
+ ent->output_command ? ent->output_command : "--+--");
|
||
+ fprintf(stderr,"\n");
|
||
+ }
|
||
+
|
||
+ if(description != NULL) free(description);
|
||
+ if(mgcsfx_type != NULL) free(mgcsfx_type);
|
||
+ if(offset != NULL) free(offset);
|
||
+ if(magic != NULL) free(magic);
|
||
+ if(suffix != NULL) free(suffix);
|
||
+ if(i_img != NULL) free(i_img);
|
||
+ if(i_com != NULL) free(i_com);
|
||
+ if(o_img != NULL) free(o_img);
|
||
+ if(o_com != NULL) free(o_com);
|
||
+
|
||
+
|
||
+ if(def_err != 0) goto next3;
|
||
+
|
||
+ /* Override any existing entry for this magic number/file type */
|
||
+ for(entry = mgcsfx_table; *entry; entry = &((*entry)->next)){
|
||
+ if((ent->mgcsfx_type == (*entry)->mgcsfx_type) &&
|
||
+ (
|
||
+ ((ent->offset == (*entry)->offset) &&
|
||
+ (((ent->mgcsfx_type == T_BEINT16) &&
|
||
+ (ent->dt.int16_data == (*entry)->dt.int16_data)) ||
|
||
+ ((ent->mgcsfx_type == T_BEINT32) &&
|
||
+ (ent->dt.int32_data == (*entry)->dt.int32_data)) ||
|
||
+ ((ent->mgcsfx_type == T_LEINT16) &&
|
||
+ (ent->dt.int16_data == (*entry)->dt.int16_data)) ||
|
||
+ ((ent->mgcsfx_type == T_LEINT32) &&
|
||
+ (ent->dt.int32_data == (*entry)->dt.int32_data)) ||
|
||
+
|
||
+ ((ent->mgcsfx_type == T_MAGIC) &&
|
||
+ !memcmp(ent->dt.string_data, (*entry)->dt.string_data,
|
||
+ ent->string_len))
|
||
+ )) ||
|
||
+ ((ent->mgcsfx_type == T_SUFFIX) &&
|
||
+ !strcmp(ent->suffix, (*entry)->suffix))
|
||
+ )
|
||
+ ){
|
||
+
|
||
+ free ((*entry)->description);
|
||
+ (*entry)->description = ent->description;
|
||
+ ent->description = NULL;
|
||
+
|
||
+ (*entry)->input_image_type = ent->input_image_type;
|
||
+ if ((*entry)->input_command) free ((*entry)->input_command);
|
||
+ (*entry)->input_command = ent->input_command;
|
||
+ ent->input_command = NULL;
|
||
+
|
||
+ (*entry)->output_image_type = ent->output_image_type;
|
||
+ if ((*entry)->output_command) free ((*entry)->output_command);
|
||
+ (*entry)->output_command = ent->output_command;
|
||
+ ent->output_command = NULL;
|
||
+
|
||
+ free_mgcsfx(ent);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if (!*entry){
|
||
+ ent->next = NULL;
|
||
+ *entry = ent;
|
||
+ }
|
||
+
|
||
+ /* if(s == NULL) break; */
|
||
+next3:;
|
||
+ if(def_err != 0) free_mgcsfx(ent);
|
||
+ } /* end of while(1) */
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%^%8%C%/%J%s%P!<Dj5A%U%!%$%kL>$rF@$F!"FI$_9~$^$;$k(B */
|
||
+static void init_mgcsfx ()
|
||
+{
|
||
+ extern char *getenv ();
|
||
+
|
||
+ char *home_dir;
|
||
+ char fname[1024];
|
||
+ mgcsfxtab *entry;
|
||
+ int len;
|
||
+ struct stat st;
|
||
+
|
||
+#ifdef USE_MGCSFX_PREPROCESSOR
|
||
+ char *pp_fname;
|
||
+#endif /* USE_MGCSFX_PREPROCESSOR */
|
||
+
|
||
+ mgcsfx_table = NULL;
|
||
+
|
||
+ mgcsfx_handler_setup();
|
||
+
|
||
+ if(nomgcsfx){
|
||
+ mgcsfx_setup_flag = 1;
|
||
+ nitem_mgcsfx = 0;
|
||
+ desc_width = 0;
|
||
+ }else{
|
||
+ sprintf (fname, "%s/%s", SYSCONFDIR, MGCSFX_SITE_RC);
|
||
+ if(stat(fname, &st) == 0 && S_ISREG(st.st_mode)){
|
||
+ /* Read the site MagicSuffix table into a linked list */
|
||
+#ifdef USE_MGCSFX_PREPROCESSOR
|
||
+ if((pp_fname = make_preprocessed_file(fname)) != NULL){
|
||
+ read_mgcsfx (&mgcsfx_table, pp_fname);
|
||
+ }
|
||
+ unlink(pp_fname);
|
||
+#else
|
||
+ read_mgcsfx (&mgcsfx_table, fname);
|
||
+#endif /* USE_MGCSFX_PREPROCESSOR */
|
||
+ }
|
||
+
|
||
+ /* Read the personal MgcSfx table into the list overriding site entries */
|
||
+ if ((home_dir = getenv ("HOME"))){
|
||
+ sprintf (fname, "%s/%s", home_dir, MGCSFX_RC);
|
||
+ if(stat(fname, &st) == 0 && S_ISREG(st.st_mode)){
|
||
+#ifdef USE_MGCSFX_PREPROCESSOR
|
||
+ if((pp_fname = make_preprocessed_file(fname)) != NULL){
|
||
+ read_mgcsfx (&mgcsfx_table, pp_fname);
|
||
+ }
|
||
+ unlink(pp_fname);
|
||
+#else
|
||
+ read_mgcsfx (&mgcsfx_table, fname);
|
||
+#endif /* USE_MGCSFX_PREPROCESSOR */
|
||
+ }
|
||
+ }
|
||
+
|
||
+ mgcsfx_setup_flag = 1;
|
||
+
|
||
+ nitem_mgcsfx = 0;
|
||
+ desc_width = 0;
|
||
+ for (entry = mgcsfx_table; entry; entry = entry->next){
|
||
+ nitem_mgcsfx ++;
|
||
+ len = strlen(entry->description);
|
||
+ if(len > desc_width) desc_width = len;
|
||
+ if(max_offset_mgcsfx < entry->offset) max_offset_mgcsfx = entry->offset;
|
||
+ if(entry->mgcsfx_type == T_MAGIC &&
|
||
+ max_length_mgcsfx < entry->string_len)
|
||
+ max_length_mgcsfx = entry->string_len;
|
||
+ }
|
||
+ if(max_length_mgcsfx == 0) max_length_mgcsfx = sizeof(int32);
|
||
+ need_buf_size = max_offset_mgcsfx + max_length_mgcsfx + 1;/* 1 is safety */
|
||
+ }
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%^%8%C%/%J%s%P!<$rD4$Y$F!"Dj5A$7$F$$$k%F!<%V%k$r8!:w$9$k(B
|
||
+ $B%^%8%C%/%J%s%P!<$N%F!<%V%k$rFI$_9~$s$G$$$J$$$J$iFI$_9~$`(B */
|
||
+static mgcsfxtab *find_mgcsfx (fname, buffer, buffer_size)
|
||
+ char *fname;
|
||
+ unsigned char *buffer;
|
||
+ int buffer_size;
|
||
+{
|
||
+ mgcsfxtab *entry;
|
||
+ int16 buf16;
|
||
+ int32 buf32;
|
||
+ char *suf;
|
||
+
|
||
+ if (mgcsfx_setup_flag == 0) init_mgcsfx ();
|
||
+
|
||
+ for (entry = mgcsfx_table; entry; entry = entry->next){
|
||
+ switch (entry->mgcsfx_type){
|
||
+ case T_BEINT16:
|
||
+ if ((buffer_size > 0) &&
|
||
+ ((entry->offset + sizeof (int16)) <= buffer_size)){
|
||
+ buf16 = ((char)*(buffer + entry->offset) << 8) |
|
||
+ ((char)*(buffer + entry->offset +1));
|
||
+ if(entry->dt.int16_data == buf16) return entry;
|
||
+ }
|
||
+ break;
|
||
+ case T_LEINT16:
|
||
+ if ((buffer_size > 0) &&
|
||
+ ((entry->offset + sizeof (int16)) <= buffer_size)){
|
||
+ buf16 = ((char)*(buffer + entry->offset +1) << 8) |
|
||
+ ((char)*(buffer + entry->offset));
|
||
+ if(entry->dt.int16_data == buf16) return entry;
|
||
+ }
|
||
+ break;
|
||
+ case T_BEINT32:
|
||
+ if ((buffer_size > 0) &&
|
||
+ ((entry->offset + sizeof (int32)) <= buffer_size)){
|
||
+ buf32 = ((char)*(buffer + entry->offset) << 24) |
|
||
+ ((char)*(buffer + entry->offset +1) << 16) |
|
||
+ ((char)*(buffer + entry->offset +2) << 8) |
|
||
+ ((char)*(buffer + entry->offset +3));
|
||
+ if(entry->dt.int32_data == buf32) return entry;
|
||
+ }
|
||
+ break;
|
||
+ case T_LEINT32:
|
||
+ if ((buffer_size > 0) &&
|
||
+ ((entry->offset + sizeof (int32)) <= buffer_size)){
|
||
+ buf32 = ((char)*(buffer + entry->offset +3) << 24) |
|
||
+ ((char)*(buffer + entry->offset +2) << 16) |
|
||
+ ((char)*(buffer + entry->offset +1) << 8) |
|
||
+ ((char)*(buffer + entry->offset));
|
||
+ if(entry->dt.int32_data == buf32) return entry;
|
||
+ }
|
||
+ break;
|
||
+ case T_MAGIC:
|
||
+ if ((buffer_size > 0) &&
|
||
+ ((entry->offset + entry->string_len)
|
||
+ <= buffer_size) &&
|
||
+ !memcmp (entry->dt.string_data, buffer + entry->offset,
|
||
+ entry->string_len ))
|
||
+ return entry;
|
||
+ break;
|
||
+ case T_SUFFIX:
|
||
+ if(fname != NULL && entry->suffix != NULL){
|
||
+ if(strlen(fname) - strlen(entry->suffix) > 0){
|
||
+ suf = fname + (strlen(fname) - strlen(entry->suffix));
|
||
+ if(!strcmp(suf, entry->suffix)) return entry;
|
||
+ }
|
||
+ }
|
||
+ break;
|
||
+ case T_UNKNOWN:
|
||
+ default:
|
||
+ return NULL;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%^%8%C%/%J%s%P!<$NDj5A$rD4$Y$F!"$=$l$K$"$o$;$?%3%^%s%I$r<B9T$9$k(B */
|
||
+/* if OK return 1, else if ERROR return 0 */
|
||
+int
|
||
+LoadMGCSFX(file_name, pinfo)
|
||
+ char *file_name;
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ unsigned char *buffer;
|
||
+ int size;
|
||
+ mgcsfxtab *magic;
|
||
+ mgcsfxtab *magic_cur;
|
||
+ char *ptr;
|
||
+ char command[1024];
|
||
+ int fd[2];
|
||
+ int pid = -2;
|
||
+ int file;
|
||
+ char *fname;
|
||
+ int rv;
|
||
+ int pst;
|
||
+
|
||
+ int i_it;
|
||
+ char *i_com;
|
||
+
|
||
+ WaitCursor();
|
||
+
|
||
+ fname = file_name;
|
||
+ if((file = open (fname, O_RDONLY))<0){
|
||
+ SetISTR(ISTR_WARNING, "Can't open %s",fname);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if((buffer = (unsigned char *)calloc(need_buf_size, sizeof(char))) == NULL){
|
||
+ SetISTR(ISTR_WARNING, "Can't allocate memory");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ magic_cur = NULL;
|
||
+
|
||
+/* do{ */
|
||
+ size = read (file, buffer, need_buf_size);
|
||
+
|
||
+ if (lseek (file, 0L, 0) < 0){ /* can't seek pipe !! */
|
||
+ fprintf (stderr, "Can't lseek %s\n", file_name);
|
||
+ close(file);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ magic = find_mgcsfx (fname, buffer, size);
|
||
+
|
||
+ if ((magic != NULL && magic->input_command) ||
|
||
+ (magic == NULL && mgcsfx && input_command_ex_flag)){
|
||
+
|
||
+ if(magic == NULL){
|
||
+ if (fname != NULL && (ptr = strstr(input_command_ex, "%s"))){
|
||
+ sprintf (command, input_command_ex, fname);
|
||
+ }else{
|
||
+ strcpy (command, input_command_ex);
|
||
+ fname=NULL;
|
||
+ }
|
||
+ }else{
|
||
+ /* Use stdin or give file name */
|
||
+ if (fname != NULL && (ptr = strstr(magic->input_command, "%s"))){
|
||
+ sprintf (command, magic->input_command, fname);
|
||
+ }else{
|
||
+ strcpy (command, magic->input_command);
|
||
+ fname=NULL;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Do the pipe/fork/exec here */
|
||
+ if (pipe (fd) < 0){
|
||
+ fprintf (stderr, "Can't pipe : %s\n", file_name);
|
||
+ close(file);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if ((pid = vfork ()) < 0){
|
||
+ fprintf (stderr, "Can't vfork : %s\n", file_name);
|
||
+ close (fd[0]);
|
||
+ close (fd[1]);
|
||
+ close(file);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (!pid){
|
||
+ close(0);
|
||
+ if (fname == NULL || (open ("/dev/null", O_RDONLY) < 0)){
|
||
+ dup(file);
|
||
+ }
|
||
+ close(file);
|
||
+ close(1);
|
||
+ dup(fd[1]);
|
||
+ close(2);
|
||
+ open("/dev/null", O_WRONLY);
|
||
+ close(fd[0]);
|
||
+ execl("/bin/sh", "/bin/sh", "-c", command, 0);
|
||
+ _exit(127);
|
||
+ }
|
||
+
|
||
+ close (fd[1]);
|
||
+ dup2(fd[0], file);
|
||
+ close (fd[0]);
|
||
+ fname = NULL;
|
||
+ magic_cur = magic;
|
||
+ }
|
||
+/* } while(magic != NULL); */
|
||
+
|
||
+ free(buffer);
|
||
+
|
||
+ if(magic_cur == NULL && mgcsfx && input_command_ex_flag){
|
||
+ i_it = IT_PNM;
|
||
+ i_com = input_command_ex;
|
||
+ }else{
|
||
+ i_it = magic_cur->input_image_type;
|
||
+ i_com = magic_cur->input_command;
|
||
+ }
|
||
+
|
||
+ if((magic_cur != NULL && i_com) ||
|
||
+ (magic_cur == NULL && mgcsfx && input_command_ex_flag)){
|
||
+ switch(i_it){
|
||
+ case IT_PNM:
|
||
+ case IT_PPM:
|
||
+ case IT_PGM:
|
||
+ case IT_PBM:
|
||
+ case IT_PNM_RAW:
|
||
+ case IT_PPM_RAW:
|
||
+ case IT_PGM_RAW:
|
||
+ case IT_PBM_RAW:
|
||
+ case IT_PNM_ASCII:
|
||
+ case IT_PPM_ASCII:
|
||
+ case IT_PGM_ASCII:
|
||
+ case IT_PBM_ASCII:
|
||
+ rv = LoadPBM(file_name, pinfo, file);
|
||
+ break;
|
||
+ case IT_GIF:
|
||
+ case IT_JPEG:
|
||
+ case IT_TIFF:
|
||
+ case IT_JFIF:
|
||
+ case IT_XBM:
|
||
+ case IT_XPM:
|
||
+ case IT_BMP:
|
||
+ case IT_SUNRAS:
|
||
+ case IT_IRIS:
|
||
+ case IT_XWD:
|
||
+ case IT_MAG:
|
||
+ case IT_MAKI:
|
||
+ case IT_PI:
|
||
+ case IT_PIC:
|
||
+ case IT_PIC2:
|
||
+ SetISTR(ISTR_WARNING, "Yet supported input image type (from filter output)");
|
||
+ rv = 0;
|
||
+ break;
|
||
+ case IT_UNKNOWN:
|
||
+ SetISTR(ISTR_WARNING, "Unknown input image type (from filter output)");
|
||
+ rv = 0;
|
||
+ break;
|
||
+#ifdef HAVE_MGCSFX_AUTO
|
||
+ case IT_AUTO:
|
||
+#endif
|
||
+ default:
|
||
+ SetISTR(ISTR_WARNING, "Error in input image type (from filter output)");
|
||
+ rv = 0;
|
||
+ break;
|
||
+ }
|
||
+ }else{
|
||
+ rv = 0;
|
||
+ }
|
||
+
|
||
+ /* fail if pid still == -2? */
|
||
+ while(wait(&pst) != pid); /* FIXME? pid isn't necessarily initialized... */
|
||
+ if( *((char *)&pst) != 0 ) rv = 0;
|
||
+
|
||
+ input_command_ex_flag = 0;
|
||
+
|
||
+ return rv;
|
||
+
|
||
+ /* fclose(fp); close in Load??? */
|
||
+ /* return 0; error */
|
||
+ /* return 1; ok */
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+/*--------------------------------------------------------------------------*/
|
||
+#ifndef MGCSFX_DEFAULT_INPUT_COMMAND
|
||
+# define MGCSFX_DEFAULT_INPUT_COMMAND "tifftopnm"
|
||
+#endif
|
||
+#ifndef MGCSFX_DEFAULT_OUTPUT_COMMAND
|
||
+# define MGCSFX_DEFAULT_OUTPUT_COMMAND "pnmtotiff"
|
||
+#endif
|
||
+
|
||
+int MSWIDE = 0;
|
||
+int MSHIGH = 0;
|
||
+
|
||
+#define MS_NBUTTS 2
|
||
+#define MS_BOK 0
|
||
+#define MS_BCANC 1
|
||
+#define BUTTW 60 /* width of buttons (OK or Cancel) */
|
||
+#define BUTTH 24 /* height of buttons (OK or Cancel) */
|
||
+#define RBSIZE 15 /* width and height of RB button (select, ON or OFF)*/
|
||
+#define CWIDE 8 /* width of character */
|
||
+/* #define CHIGH height of character defined in xv.h */
|
||
+#define MARGIN 3 /* margin of button and label SPACING */
|
||
+
|
||
+#define MSD_TITLE "Save file with external command..."
|
||
+#define MSD_RBTITLE "Type of Magic and Suffix"
|
||
+#define MSD_IC_TITLE "input command"
|
||
+
|
||
+static BUTT msbut[MS_NBUTTS];
|
||
+static RBUTT *typeRB;
|
||
+
|
||
+static char output_command_ex[1024];
|
||
+static int output_command_ex_flag = 0;
|
||
+
|
||
+static int colorType;
|
||
+
|
||
+static int w_pid;
|
||
+static int w_pstatus;
|
||
+
|
||
+#define MSNAMWIDE 252 /* width of 'file name' entry window */
|
||
+#define MAXFNLEN 256 /* max len of filename being entered */
|
||
+static char DialogFileName[MAXFNLEN+100]; /* filename being entered */
|
||
+static int curPos, stPos, enPos; /* filename textedit stuff */
|
||
+
|
||
+
|
||
+static mgcsfxtab *get_mgcsfx PARM((int));
|
||
+static void changeSuffix PARM((int));
|
||
+
|
||
+static int WriteMGCSFX PARM((FILE**,byte*,int,int,int,
|
||
+ byte*,byte*,byte*,int,int,char*,
|
||
+ int, int, char*));
|
||
+void CreateMGCSFXW PARM((void));
|
||
+void MGCSFXDialog PARM((int));
|
||
+int MGCSFXCheckEvent PARM((XEvent *));
|
||
+int MGCSFXSaveParams PARM((char *, int));
|
||
+
|
||
+static void drawMSD PARM((int,int,int,int));
|
||
+static void clickMSD PARM((int,int));
|
||
+static void doCmd PARM((int));
|
||
+static int writeMGCSFX PARM((void));
|
||
+
|
||
+static void changeSuffix PARM((int));
|
||
+static void redrawNamMSD PARM((void));
|
||
+static void showFNamMSD PARM((void));
|
||
+static int keyinMSD PARM((int));
|
||
+
|
||
+int getInputCom PARM((void));
|
||
+int getOutputCom PARM((void));
|
||
+/*--------------------------------------------------------------------------*/
|
||
+
|
||
+/***************************************************/
|
||
+/* $B$I$l$rA*$s$@$+D4$Y$k!##0$O%3%^%s%I$rF~NO$9$k$b$N$H$9$k(B */
|
||
+static mgcsfxtab *get_mgcsfx(ms_type)
|
||
+ int ms_type;
|
||
+{
|
||
+ mgcsfxtab *magic;
|
||
+ int i;
|
||
+
|
||
+ magic = NULL;
|
||
+ if(ms_type != 0){
|
||
+ i = 1;
|
||
+ for(magic = mgcsfx_table; (magic && i<ms_type); magic = magic->next){i++;}
|
||
+ }
|
||
+ return magic;
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+/* $B30It%3%^%s%I$r<B9T$7$F!"$=$l$K=PNO$9$k(B */
|
||
+/* if OK return 0, else if ERROR return -1 */
|
||
+static
|
||
+int WriteMGCSFX(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,file_name,
|
||
+ ms_type, file, comment)
|
||
+ FILE **fp;
|
||
+ byte *pic;
|
||
+ int ptype, w,h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int numcols, colorstyle;
|
||
+ char *file_name;
|
||
+ int ms_type;
|
||
+ int file; /* file descriptor */
|
||
+ char *comment;
|
||
+{
|
||
+ mgcsfxtab *magic;
|
||
+
|
||
+ int fd[2];
|
||
+ int pid;
|
||
+ int rv;
|
||
+
|
||
+ WaitCursor();
|
||
+
|
||
+#ifdef USE_SIGCHLD
|
||
+ w_p_fail = 1;
|
||
+#endif
|
||
+
|
||
+ magic = get_mgcsfx(ms_type);
|
||
+ if(ms_type != 0 && magic == NULL) return -1;
|
||
+
|
||
+ if ((ms_type == 0 && output_command_ex_flag) ||
|
||
+ (ms_type !=0 && magic != NULL && magic->output_command)){
|
||
+
|
||
+ /* Do the pipe/fork/exec here */
|
||
+ if (pipe (fd) < 0){
|
||
+ fprintf (stderr, "Can't pipe : %s\n", file_name);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ if ((pid = vfork ()) < 0){
|
||
+ fprintf (stderr, "Can't vfork : %s\n", file_name);
|
||
+ close (fd[0]);
|
||
+ close (fd[1]);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ if (!pid){
|
||
+ close(1);
|
||
+ dup(file);
|
||
+ close(file);
|
||
+ close(0);
|
||
+ dup(fd[0]);
|
||
+ close(2);
|
||
+ open("/dev/null", O_WRONLY);
|
||
+ close(fd[1]);
|
||
+ if(ms_type == 0){
|
||
+ execl("/bin/sh", "/bin/sh", "-c", output_command_ex, 0);
|
||
+ }else{
|
||
+ execl("/bin/sh", "/bin/sh", "-c", magic->output_command, 0);
|
||
+ }
|
||
+ _exit(127);
|
||
+ }
|
||
+
|
||
+ close (fd[0]);
|
||
+ dup2(fd[1], file);
|
||
+ close (fd[1]);
|
||
+
|
||
+ }else{
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+
|
||
+ *fp = fdopen(file, "w");
|
||
+
|
||
+ /* sleep(1); Best way is wait for checking SIGCHLD, but it's feel waist.*/
|
||
+
|
||
+#ifdef USE_SIGCHLD
|
||
+ if(w_p_fail != 2){
|
||
+#endif
|
||
+ if(ms_type == 0){
|
||
+ rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,
|
||
+ 1, comment);
|
||
+ }else{
|
||
+ switch(magic -> output_image_type){
|
||
+ case IT_PNM:
|
||
+ case IT_PPM:
|
||
+ case IT_PGM:
|
||
+ case IT_PBM:
|
||
+ case IT_PNM_RAW:
|
||
+ case IT_PPM_RAW:
|
||
+ case IT_PGM_RAW:
|
||
+ case IT_PBM_RAW:
|
||
+ rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,
|
||
+ 1, comment);
|
||
+ break;
|
||
+ case IT_PNM_ASCII:
|
||
+ case IT_PPM_ASCII:
|
||
+ case IT_PGM_ASCII:
|
||
+ case IT_PBM_ASCII:
|
||
+ rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,
|
||
+ 0, comment);
|
||
+ break;
|
||
+ case IT_GIF:
|
||
+ case IT_JPEG:
|
||
+ case IT_TIFF:
|
||
+ case IT_JFIF:
|
||
+ case IT_XBM:
|
||
+ case IT_XPM:
|
||
+ case IT_BMP:
|
||
+ case IT_SUNRAS:
|
||
+ case IT_IRIS:
|
||
+ case IT_XWD:
|
||
+ case IT_MAG:
|
||
+ case IT_MAKI:
|
||
+ case IT_PI:
|
||
+ case IT_PIC:
|
||
+ case IT_PIC2:
|
||
+ SetISTR(ISTR_WARNING, "Yet supported output image type (to filter input)");
|
||
+ rv = -1;
|
||
+ break;
|
||
+ case IT_UNKNOWN:
|
||
+ SetISTR(ISTR_WARNING, "Unknown output image type (to filter input)");
|
||
+ rv = -1;
|
||
+ break;
|
||
+#ifdef HAVE_MGCSFX_AUTO
|
||
+ case IT_AUTO:
|
||
+#endif
|
||
+ default:
|
||
+ SetISTR(ISTR_WARNING, "Error in output image type (to filter input)");
|
||
+ rv = -1;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+#ifdef USE_SIGCHLD
|
||
+ }else{
|
||
+ rv = -1;
|
||
+ }
|
||
+#endif
|
||
+
|
||
+#ifdef USE_SIGCHLD
|
||
+ if(w_p_fail != 2){
|
||
+#endif
|
||
+ w_pid = pid;
|
||
+#ifdef USE_SIGCHLD
|
||
+ w_p_fail = 0;
|
||
+ }else{
|
||
+ rv = -1;
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ output_command_ex_flag = 0;
|
||
+
|
||
+ return rv;
|
||
+
|
||
+ /* fclose(*fp); close in CloseOutFile in writeMGCSFX */
|
||
+ /* return 0; ok */
|
||
+ /* return -1; error */
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+void CreateMGCSFXW()
|
||
+{
|
||
+ int y;
|
||
+ int type_num;
|
||
+ mgcsfxtab *entry;
|
||
+
|
||
+ if (mgcsfx_setup_flag == 0) init_mgcsfx ();
|
||
+
|
||
+ if(desc_width < strlen(MSD_IC_TITLE)) desc_width = strlen(MSD_IC_TITLE);
|
||
+ nitem_mgcsfx ++;
|
||
+
|
||
+ MSWIDE = desc_width * CWIDE + RBSIZE + 36; /* 36 is start of RB button */
|
||
+ MSHIGH = nitem_mgcsfx * (RBSIZE + MARGIN);
|
||
+
|
||
+ if(MSWIDE < strlen(MSD_TITLE) + 20) MSWIDE = strlen(MSD_TITLE) + 20;
|
||
+ if(MSWIDE < strlen(MSD_RBTITLE) + 16) MSWIDE = strlen(MSD_RBTITLE) + 16;
|
||
+ if(MSWIDE < MSNAMWIDE + 10) MSWIDE = MSNAMWIDE + 10;
|
||
+ if(MSWIDE < BUTTW * 2 + 10) MSWIDE = BUTTW * 2 + 10;
|
||
+
|
||
+ MSHIGH += 55 + LINEHIGH + 10 + BUTTH + 10;
|
||
+
|
||
+ MSWIDE += 20; /* right side margin */
|
||
+ MSHIGH += 10; /* RB buttun down side margin */
|
||
+
|
||
+
|
||
+ mgcsfxW = CreateWindow("xv mgcsfx", "XVmgcsfx", NULL,
|
||
+ MSWIDE, MSHIGH, infofg, infobg, 0);
|
||
+ if (!mgcsfxW) FatalError("can't create mgcsfx window!");
|
||
+
|
||
+ XSelectInput(theDisp, mgcsfxW,
|
||
+ ExposureMask | ButtonPressMask | KeyPressMask);
|
||
+
|
||
+ mgcsfxNameW = XCreateSimpleWindow(theDisp, mgcsfxW,
|
||
+ 10, MSHIGH-LINEHIGH-10-BUTTH-10-1,
|
||
+ (u_int) MSNAMWIDE+6, (u_int) LINEHIGH+5,
|
||
+ 1, infofg, infobg);
|
||
+ if (!mgcsfxNameW) FatalError("can't create mgcsfx name window");
|
||
+ XSelectInput(theDisp, mgcsfxNameW, ExposureMask);
|
||
+
|
||
+ /* Ok $B%\%?%s(B */
|
||
+ BTCreate(&msbut[MS_BOK], mgcsfxW,
|
||
+ MSWIDE-BUTTW-10-BUTTW-10-1, MSHIGH-BUTTH-10-1,
|
||
+ BUTTW, BUTTH,
|
||
+ "Ok", infofg, infobg, hicol, locol);
|
||
+ /* Cancel $B%\%?%s(B*/
|
||
+ BTCreate(&msbut[MS_BCANC], mgcsfxW,
|
||
+ MSWIDE-BUTTW-10-1, MSHIGH-BUTTH-10-1,
|
||
+ BUTTW, BUTTH,
|
||
+ "Cancel", infofg, infobg, hicol, locol);
|
||
+
|
||
+ y = 55;
|
||
+ /* User should input command to exec external command */
|
||
+ typeRB = RBCreate(NULL, mgcsfxW, 36, y, MSD_IC_TITLE,
|
||
+ infofg, infobg,hicol,locol);
|
||
+ y += (RBSIZE + MARGIN); /* 18 */
|
||
+
|
||
+ type_num = 1;
|
||
+ for (entry = mgcsfx_table; entry; entry = entry->next){
|
||
+ RBCreate(typeRB, mgcsfxW, 36, y, entry->description,
|
||
+ infofg, infobg,hicol,locol);
|
||
+ y += (RBSIZE + MARGIN); /* 18 */
|
||
+ if(entry->output_command == NULL){
|
||
+ RBSetActive(typeRB, type_num, 0); /* if no command, off */
|
||
+ }
|
||
+ type_num++;
|
||
+ }
|
||
+
|
||
+ XMapSubwindows(theDisp, mgcsfxW);
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+void MGCSFXDialog(vis)
|
||
+ int vis;
|
||
+{
|
||
+ if (vis) {
|
||
+ CenterMapWindow(mgcsfxW, msbut[MS_BOK].x + msbut[MS_BOK].w/2,
|
||
+ msbut[MS_BOK].y + msbut[MS_BOK].h/2, MSWIDE, MSHIGH);
|
||
+ }
|
||
+ else XUnmapWindow(theDisp, mgcsfxW);
|
||
+ mgcsfxUp = vis;
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+int MGCSFXCheckEvent(xev)
|
||
+ XEvent *xev;
|
||
+{
|
||
+ /* check event to see if it's for one of our subwindows. If it is,
|
||
+ deal accordingly, and return '1'. Otherwise, return '0' */
|
||
+
|
||
+ int rv;
|
||
+ rv = 1;
|
||
+
|
||
+ if (!mgcsfxUp) return (0);
|
||
+
|
||
+ if (xev->type == Expose) {
|
||
+ int x,y,w,h;
|
||
+ XExposeEvent *e = (XExposeEvent *) xev;
|
||
+ x = e->x; y = e->y; w = e->width; h = e->height;
|
||
+
|
||
+ if (e->window == mgcsfxW) drawMSD(x, y, w, h);
|
||
+ else rv = 0;
|
||
+ }
|
||
+
|
||
+ else if (xev->type == ButtonPress) {
|
||
+ XButtonEvent *e = (XButtonEvent *) xev;
|
||
+ int x,y;
|
||
+ x = e->x; y = e->y;
|
||
+
|
||
+ if (e->button == Button1) {
|
||
+ if (e->window == mgcsfxW) clickMSD(x,y);
|
||
+ else rv = 0;
|
||
+ } /* button1 */
|
||
+ else rv = 0;
|
||
+ } /* button press */
|
||
+
|
||
+ else if (xev->type == KeyPress) {
|
||
+ XKeyEvent *e = (XKeyEvent *) xev;
|
||
+ char buf[128]; KeySym ks; XComposeStatus status;
|
||
+ int stlen;
|
||
+
|
||
+ stlen = XLookupString(e,buf,128,&ks,&status);
|
||
+ buf[stlen] = '\0';
|
||
+
|
||
+ if (e->window == mgcsfxW) {
|
||
+ if (stlen) {
|
||
+ keyinMSD(buf[0]);
|
||
+ }
|
||
+ }
|
||
+ else rv = 0;
|
||
+ }
|
||
+ else rv = 0;
|
||
+
|
||
+ if (rv == 0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
|
||
+ XBell(theDisp, 50);
|
||
+ rv = 1; /* eat it */
|
||
+ }
|
||
+
|
||
+ return (rv);
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+int MGCSFXSaveParams(fname, col)
|
||
+ char *fname;
|
||
+ int col;
|
||
+{
|
||
+ colorType = col;
|
||
+ strcpy(DialogFileName, GetDirFName());
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%@%$%"%m%0$rI=<($9$k$H$-$N=hM}(B */
|
||
+static void drawMSD(x,y,w,h)
|
||
+ int x,y,w,h;
|
||
+{
|
||
+ int i;
|
||
+ XRectangle xr;
|
||
+
|
||
+ xr.x = x; xr.y = y; xr.width = w; xr.height = h;
|
||
+ XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
|
||
+
|
||
+ XSetForeground(theDisp, theGC, infofg);
|
||
+ XSetBackground(theDisp, theGC, infobg);
|
||
+
|
||
+ for (i = 0; i < MS_NBUTTS; i++) BTRedraw(&msbut[i]);
|
||
+
|
||
+ ULineString(mgcsfxW, typeRB->x-16, typeRB->y-3-DESCENT,
|
||
+ MSD_RBTITLE);
|
||
+ RBRedraw(typeRB, -1);
|
||
+
|
||
+ DrawString(mgcsfxW, 20, 29, MSD_TITLE);
|
||
+
|
||
+ XSetClipMask(theDisp, theGC, None);
|
||
+
|
||
+ showFNamMSD();
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%@%$%"%m%0$r%/%j%C%/$7$?$H$-$N=hM}(B */
|
||
+static void clickMSD(x,y)
|
||
+ int x,y;
|
||
+{
|
||
+ int i;
|
||
+ BUTT *bp;
|
||
+
|
||
+ /* check BUTTs */
|
||
+
|
||
+ /* check the RBUTTS first, since they don't DO anything */
|
||
+ if ((i = RBClick(typeRB, x,y)) >= 0) { /* $BA*Br(B(type)$B%\%?%s$N=hM}(B */
|
||
+ (void) RBTrack(typeRB, i); /* $BA*Br(B(type)$B%\%?%s$r2!$7$?$H$-(B */
|
||
+ changeSuffix(i);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ for (i = 0; i < MS_NBUTTS; i++) { /* Ok,Cancel $B%\%?%s$N=hM}(B */
|
||
+ bp = &msbut[i];
|
||
+ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h))
|
||
+ break;
|
||
+ }
|
||
+ if (i < MS_NBUTTS) /* found one */ /* Ok,Cancel $B%\%?%s$r2!$7$?$H$-(B */
|
||
+ if (BTTrack(bp)) doCmd(i);
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%\%?%s(B(Ok, Cancel) $B$N=hM}(B */
|
||
+static void doCmd(cmd)
|
||
+ int cmd;
|
||
+{
|
||
+ int rv;
|
||
+
|
||
+ switch (cmd) {
|
||
+ case MS_BOK: /* Ok button */ {
|
||
+ char *fullname;
|
||
+
|
||
+ rv = writeMGCSFX(); /* Save with filter(MGCSFX) */
|
||
+ MGCSFXDialog(0);
|
||
+
|
||
+ fullname = GetDirFullName();
|
||
+ if (!ISPIPE(fullname[0])) {
|
||
+ XVCreatedFile(fullname);
|
||
+ if(!rv) StickInCtrlList(0);
|
||
+ }
|
||
+ }
|
||
+ break;
|
||
+ case MS_BCANC: /* Cancel button */
|
||
+ DialogFileName[0] = '\0';
|
||
+ curPos = stPos = enPos = 0;
|
||
+ MGCSFXDialog(0);
|
||
+ break;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*******************************************/
|
||
+static int writeMGCSFX()
|
||
+{
|
||
+ int rv, type;
|
||
+ int ptype, w, h, pfree, nc;
|
||
+ byte *inpix, *rmap, *gmap, *bmap;
|
||
+
|
||
+ FILE *fp = NULL;
|
||
+ int file;
|
||
+ char *fullname;
|
||
+
|
||
+ rv = -1;
|
||
+ type = RBWhich(typeRB);
|
||
+
|
||
+ SetDirFName(DialogFileName); /* change filename in dir dialog */
|
||
+ fullname = GetDirFullName();
|
||
+
|
||
+ if(type == 0){
|
||
+ if(getOutputCom() == 0) return rv;
|
||
+ }
|
||
+
|
||
+ file = OpenOutFileDesc(fullname);
|
||
+ if(file < 0) return rv;
|
||
+
|
||
+ WaitCursor();
|
||
+ inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
|
||
+
|
||
+ rv = WriteMGCSFX(&fp, inpix, ptype, w, h,
|
||
+ rmap, gmap, bmap, nc, colorType, fullname,
|
||
+ type, file, picComments);
|
||
+
|
||
+ SetCursors(-1);
|
||
+
|
||
+ if (CloseOutFile(fp, fullname, rv) == 0) DirBox(0);
|
||
+
|
||
+ WaitCursor();
|
||
+#ifdef USE_SIGCHLD
|
||
+ if(w_p_fail == 0){
|
||
+#endif
|
||
+ while(wait(&w_pstatus) != w_pid); /* if( *((char *)&w_pstatus) != 0 ) ; */
|
||
+#ifdef USE_SIGCHLD
|
||
+ }else{
|
||
+ w_p_fail = 0;
|
||
+ }
|
||
+#endif
|
||
+ w_pid = 0;
|
||
+ w_pstatus = 0;
|
||
+
|
||
+ if (pfree) free(inpix);
|
||
+ return rv;
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************/
|
||
+static void changeSuffix(ms_type)
|
||
+ int ms_type;
|
||
+{
|
||
+ /* see if there's a common suffix at the end of the DialogFileName.
|
||
+ if there is, remember what case it was (all caps or all lower), lop
|
||
+ it off, and replace it with a new appropriate suffix, in the
|
||
+ same case */
|
||
+
|
||
+ int allcaps;
|
||
+ char *suffix, *sp, *dp, lowsuf[512];
|
||
+ mgcsfxtab *magic;
|
||
+
|
||
+ /* find the last '.' in the DialogFileName */
|
||
+ suffix = (char *) rindex(DialogFileName, '.');
|
||
+ if (!suffix) return;
|
||
+ suffix++; /* point to first letter of the suffix */
|
||
+
|
||
+ /* check for all-caposity */
|
||
+ for (sp = suffix, allcaps=1; *sp; sp++)
|
||
+ if (islower(*sp)) allcaps = 0;
|
||
+
|
||
+ /* copy the suffix into an all-lower-case buffer */
|
||
+ for (sp=suffix, dp=lowsuf; *sp; sp++, dp++) {
|
||
+ *dp = (isupper(*sp)) ? tolower(*sp) : *sp;
|
||
+ }
|
||
+ *dp = '\0';
|
||
+
|
||
+
|
||
+ magic = get_mgcsfx(ms_type);
|
||
+ if(magic != NULL && magic->suffix != NULL){
|
||
+ strcpy(lowsuf,(magic->suffix)+1);
|
||
+
|
||
+ if (allcaps) { /* upper-caseify lowsuf */
|
||
+ for (sp=lowsuf; *sp; sp++)
|
||
+ *sp = (islower(*sp)) ? toupper(*sp) : *sp;
|
||
+ }
|
||
+
|
||
+ /* one other case: if the original suffix started with a single
|
||
+ capital letter, make the new suffix start with a single cap */
|
||
+ if (isupper(suffix[0])) lowsuf[0] = toupper(lowsuf[0]);
|
||
+
|
||
+ strcpy(suffix, lowsuf); /* tack onto DialogFileName */
|
||
+ showFNamMSD();
|
||
+ }
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%@%$%"%m%0Fb$K%U%!%$%k%M!<%`$rI=<($9$k$H$-$N=hM}(B ($B2<@A$1(B)*/
|
||
+static void redrawNamMSD()
|
||
+{
|
||
+ int cpos;
|
||
+
|
||
+ /* draw substring DialogFileName[stPos:enPos] and cursor */
|
||
+
|
||
+ Draw3dRect(mgcsfxNameW, 0, 0, (u_int) MSNAMWIDE+5, (u_int) LINEHIGH+4, R3D_IN, 2,
|
||
+ hicol, locol, infobg);
|
||
+
|
||
+ XSetForeground(theDisp, theGC, infofg);
|
||
+
|
||
+ if (stPos>0) { /* draw a "there's more over here" doowah */
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, 0,0,0,LINEHIGH+5);
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, 1,0,1,LINEHIGH+5);
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, 2,0,2,LINEHIGH+5);
|
||
+ }
|
||
+
|
||
+ if ((size_t) enPos < strlen(DialogFileName)) {
|
||
+ /* draw a "there's more over here" doowah */
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+5,0,MSNAMWIDE+5,LINEHIGH+5);
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+4,0,MSNAMWIDE+4,LINEHIGH+5);
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+3,0,MSNAMWIDE+3,LINEHIGH+5);
|
||
+ }
|
||
+
|
||
+ XDrawString(theDisp, mgcsfxNameW, theGC,3,ASCENT+3,DialogFileName+stPos, enPos-stPos);
|
||
+
|
||
+ cpos = XTextWidth(mfinfo, &DialogFileName[stPos], curPos-stPos);
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2, 3+cpos, 2+CHIGH+1);
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2+CHIGH+1, 5+cpos, 2+CHIGH+3);
|
||
+ XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2+CHIGH+1, 1+cpos, 2+CHIGH+3);
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%@%$%"%m%0Fb$K%U%!%$%k%M!<%`$rI=<($9$k(B */
|
||
+static void showFNamMSD()
|
||
+{
|
||
+ int len;
|
||
+
|
||
+ len = strlen(DialogFileName);
|
||
+
|
||
+ if (curPos<stPos) stPos = curPos;
|
||
+ if (curPos>enPos) enPos = curPos;
|
||
+
|
||
+ if (stPos>len) stPos = (len>0) ? len-1 : 0;
|
||
+ if (enPos>len) enPos = (len>0) ? len-1 : 0;
|
||
+
|
||
+ /* while substring is shorter than window, inc enPos */
|
||
+
|
||
+ while (XTextWidth(mfinfo, &DialogFileName[stPos], enPos-stPos) < MSNAMWIDE
|
||
+ && enPos<len) { enPos++; }
|
||
+
|
||
+ /* while substring is longer than window, dec enpos, unless enpos==curpos,
|
||
+ in which case, inc stpos */
|
||
+
|
||
+ while (XTextWidth(mfinfo, &DialogFileName[stPos], enPos-stPos) > MSNAMWIDE) {
|
||
+ if (enPos != curPos) enPos--;
|
||
+ else stPos++;
|
||
+ }
|
||
+
|
||
+
|
||
+ if (ctrlColor) XClearArea(theDisp, mgcsfxNameW, 2,2, (u_int) MSNAMWIDE+5-3,
|
||
+ (u_int) LINEHIGH+4-3, False);
|
||
+ else XClearWindow(theDisp, mgcsfxNameW);
|
||
+
|
||
+ redrawNamMSD();
|
||
+ BTSetActive(&msbut[MS_BOK], strlen(DialogFileName)!=0);
|
||
+}
|
||
+
|
||
+/***************************************************/
|
||
+/* $B%-!<F~NO$7$?$H$-$N=hM}(B */
|
||
+static int keyinMSD(c)
|
||
+ int c;
|
||
+{
|
||
+ /* got keypress in dirW. stick on end of DialogFileName */
|
||
+ int len;
|
||
+
|
||
+ len = strlen(DialogFileName);
|
||
+
|
||
+ if (c>=' ' && c<'\177') { /* printable characters */
|
||
+ /* note: only allow 'piped commands' in savemode... */
|
||
+
|
||
+ /* only allow spaces in 'piped commands', not filenames */
|
||
+ if (c==' ' && (!ISPIPE(DialogFileName[0]) || curPos==0)) return (-1);
|
||
+
|
||
+ /* only allow vertbars in 'piped commands', not filenames */
|
||
+ if (c=='|' && curPos!=0 && !ISPIPE(DialogFileName[0])) return(-1);
|
||
+
|
||
+ if (len >= MAXFNLEN-1) return(-1); /* max length of string */
|
||
+ xvbcopy(&DialogFileName[curPos], &DialogFileName[curPos+1], (size_t) (len-curPos+1));
|
||
+ DialogFileName[curPos]=c; curPos++;
|
||
+ }
|
||
+
|
||
+ else if (c=='\010' || c=='\177') { /* BS or DEL */
|
||
+ if (curPos==0) return(-1); /* at beginning of str */
|
||
+ xvbcopy(&DialogFileName[curPos], &DialogFileName[curPos-1], (size_t) (len-curPos+1));
|
||
+ curPos--;
|
||
+ }
|
||
+
|
||
+ else if (c=='\025') { /* ^U: clear entire line */
|
||
+ DialogFileName[0] = '\0';
|
||
+ curPos = 0;
|
||
+ }
|
||
+
|
||
+ else if (c=='\013') { /* ^K: clear to end of line */
|
||
+ DialogFileName[curPos] = '\0';
|
||
+ }
|
||
+
|
||
+ else if (c=='\001') { /* ^A: move to beginning */
|
||
+ curPos = 0;
|
||
+ }
|
||
+
|
||
+ else if (c=='\005') { /* ^E: move to end */
|
||
+ curPos = len;
|
||
+ }
|
||
+
|
||
+ else if (c=='\004') { /* ^D: delete character at curPos */
|
||
+ if (curPos==len) return(-1);
|
||
+ xvbcopy(&DialogFileName[curPos+1], &DialogFileName[curPos], (size_t) (len-curPos));
|
||
+ }
|
||
+
|
||
+ else if (c=='\002') { /* ^B: move backwards char */
|
||
+ if (curPos==0) return(-1);
|
||
+ curPos--;
|
||
+ }
|
||
+
|
||
+ else if (c=='\006') { /* ^F: move forwards char */
|
||
+ if (curPos==len) return(-1);
|
||
+ curPos++;
|
||
+ }
|
||
+
|
||
+ else if (c=='\012' || c=='\015') { /* CR(\r) or LF(\n) */
|
||
+ FakeButtonPress(&msbut[MS_BOK]);
|
||
+ }
|
||
+
|
||
+ else if (c=='\033') { /* ESC = Cancel */
|
||
+ FakeButtonPress(&msbut[MS_BCANC]);
|
||
+ }
|
||
+
|
||
+ else if (c=='\011') { /* tab = filename expansion */
|
||
+ if (1 /* !autoComplete() */) XBell(theDisp, 0);
|
||
+ else {
|
||
+ curPos = strlen(DialogFileName);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ else return(-1); /* unhandled character */
|
||
+
|
||
+ showFNamMSD();
|
||
+
|
||
+ return(0);
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+int getInputCom()
|
||
+{
|
||
+ static const char *labels[] = { "\nOk", "\033Cancel" };
|
||
+ int i;
|
||
+
|
||
+ strcpy(input_command_ex, MGCSFX_DEFAULT_INPUT_COMMAND);
|
||
+ i = GetStrPopUp("Input External Command (Input is PNM):", labels, 2,
|
||
+ input_command_ex, 1024, "",0);
|
||
+ if (i == 0 && strlen(input_command_ex) != 0){
|
||
+ input_command_ex_flag = 1;
|
||
+ return 1;
|
||
+ }else{
|
||
+ input_command_ex_flag = 0;
|
||
+ return 0;
|
||
+ }
|
||
+}
|
||
+
|
||
+int getOutputCom()
|
||
+{
|
||
+ static const char *labels[] = { "\nOk", "\033Cancel" };
|
||
+ int i;
|
||
+
|
||
+ strcpy(output_command_ex, MGCSFX_DEFAULT_OUTPUT_COMMAND);
|
||
+ i = GetStrPopUp("Input External Command (Output is PNM_RAW):", labels, 2,
|
||
+ output_command_ex, 1024, "",0);
|
||
+ if (i == 0 && strlen(output_command_ex) != 0){
|
||
+ output_command_ex_flag = 1;
|
||
+ return 1;
|
||
+ }else{
|
||
+ output_command_ex_flag = 0;
|
||
+ return 0;
|
||
+ }
|
||
+}
|
||
+
|
||
+#ifdef SVR4
|
||
+Sigfunc *
|
||
+xv_signal(signo, func)
|
||
+ int signo;
|
||
+ Sigfunc *func;
|
||
+{
|
||
+ struct sigaction act, oact;
|
||
+
|
||
+ act.sa_handler = func;
|
||
+ sigemptyset(&act.sa_mask);
|
||
+ act.sa_flags = 0;
|
||
+ act.sa_flags |= SA_RESTART;
|
||
+
|
||
+ if (sigaction(signo, &act, &oact) < 0)
|
||
+ return SIG_ERR;
|
||
+
|
||
+ return oact.sa_handler;
|
||
+}
|
||
+#endif
|
||
+
|
||
+#endif /* HAVE_MGCSFX */
|
||
diff -u -r --new-file xv-3.10a.orig/xvml.c xv-3.10a/xvml.c
|
||
--- xv-3.10a.orig/xvml.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvml.c 2005-04-18 00:57:34.000000000 -0500
|
||
@@ -0,0 +1,989 @@
|
||
+/*
|
||
+ * xvml.c - makes text item structure for multi-lingual textviewer.
|
||
+ *
|
||
+ * Entry Points:
|
||
+ * struct ml_text *ml_draw_text()
|
||
+ * struct context *ml_create_context()
|
||
+ * int ml_set_charsets()
|
||
+ * void get_monofont_size()
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+#include <X11/Xresource.h>
|
||
+
|
||
+#ifdef TV_MULTILINGUAL /* whole this file. */
|
||
+
|
||
+#include "xvml.h"
|
||
+#define HAVE_STRDUP 1
|
||
+#define USE_MULE_EXTENSION
|
||
+
|
||
+#ifndef __STDC__
|
||
+#define CHAR char
|
||
+#else
|
||
+#define CHAR int
|
||
+#endif
|
||
+
|
||
+#define CODE_SI 0x0e /* LS0 */
|
||
+#define CODE_SO 0x0f /* LS1 */
|
||
+#define CODE_SS2 ((unsigned char) 0x8e)
|
||
+#define CODE_SS3 ((unsigned char) 0x8f)
|
||
+
|
||
+int ml_tab_width = 64; /* dots */
|
||
+
|
||
+struct charset {
|
||
+ int bpc; /* bytes per char */
|
||
+ int noc; /* number of chars */
|
||
+ char designator;
|
||
+ char *registry;
|
||
+ int bit7;
|
||
+
|
||
+ int loaded;
|
||
+ char *fontname;
|
||
+
|
||
+ XFontStruct *fs;
|
||
+} charset[] = {
|
||
+ { 1, 94, 'B', "iso8859-1", 0, 0, NULL, NULL},
|
||
+ { 1, 96, 'A', "iso8859-1", 1, 0, NULL, NULL},
|
||
+ { 1, 94, '0', "omron_udc_zh-0", 0, 0, NULL, NULL},
|
||
+ { 1, 94, '2', "mulearabic-0", 0, 0, NULL, NULL},
|
||
+ { 1, 94, '3', "mulearabic-1", 0, 0, NULL, NULL},
|
||
+ { 1, 94, '4', "mulearabic-2", 0, 0, NULL, NULL},
|
||
+ { 1, 94, 'J', "jisx0201.1976-0", 0, 0, NULL, NULL},
|
||
+ { 1, 96, '0', "muleipa-1", 1, 0, NULL, NULL},
|
||
+ { 1, 96, '1', "viscii1.1-1", 1, 0, NULL, NULL},
|
||
+ { 1, 96, '2', "viscii1.1-1", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'B', "iso8859-2", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'C', "iso8859-3", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'D', "iso8859-4", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'T', "tis620.1986-0", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'F', "iso8859-7", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'G', "iso8859-6", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'H', "iso8859-8", 1, 0, NULL, NULL},
|
||
+ { 1, 94, 'I', "jisx0201.1976-0", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'L', "iso8859-5", 1, 0, NULL, NULL},
|
||
+ { 1, 96, 'M', "iso8859-9", 1, 0, NULL, NULL},
|
||
+ { 2, 94, '2', "ethio-0", 0, 0, NULL, NULL},
|
||
+ { 2, 94, '@', "jisx0208.1978", 0, 0, NULL, NULL},
|
||
+ { 2, 94, 'A', "gb2312.1980-0", 0, 0, NULL, NULL},
|
||
+ { 2, 94, 'B', "jisx0208.1983-0", 0, 0, NULL, NULL},
|
||
+ { 2, 94, 'C', "ksc5601.1987-0", 0, 0, NULL, NULL},
|
||
+ { 2, 94, 'D', "jisx0212.1990-0", 0, 0, NULL, NULL},
|
||
+ { 2, 94, '0', "big5.eten-0", 0, 0, NULL, NULL},
|
||
+ { 2, 94, '1', "big5.hku-0", 0, 0, NULL, NULL},
|
||
+ /* End Mark */
|
||
+ { 0, 0, 0, NULL, 0, 0, NULL, NULL},
|
||
+};
|
||
+#define NR_CHARSETS ((int) (sizeof charset / sizeof charset[0]))
|
||
+
|
||
+static struct charset *ascii = NULL;
|
||
+
|
||
+struct context {
|
||
+ struct charset *g[4];
|
||
+ struct charset **gl, **gr;
|
||
+ struct charset **ss;
|
||
+ int eol; /* 0: \n, 1: \r\n, 2: \r, 3: any */
|
||
+ int valid[4]; /* g[i] is valid? */
|
||
+ int short_form; /* allow shortened designator sequence? */
|
||
+ int lock_shift; /* allow locking shift? */
|
||
+
|
||
+ unsigned char *cbuf, *cbp;
|
||
+ struct ml_text text;
|
||
+ int line;
|
||
+ int delta;
|
||
+ int toolong;
|
||
+
|
||
+ Display *dpy;
|
||
+ Screen *scr;
|
||
+ Window root_win;
|
||
+};
|
||
+#define DPY (context->dpy)
|
||
+#define SCR (context->scr)
|
||
+#define ROOT_WIN (context->root_win)
|
||
+
|
||
+static unsigned char *escape_sequence PARM((unsigned char *));
|
||
+static unsigned char *designator_sequence PARM((unsigned char *));
|
||
+static void locking_shift PARM((unsigned CHAR));
|
||
+static void single_shift PARM((unsigned CHAR));
|
||
+static void put_unknown_char PARM((unsigned CHAR));
|
||
+static struct charset *search_charset PARM((int, int, int));
|
||
+static void pack_string PARM((struct charset *,
|
||
+ unsigned char *, int));
|
||
+static void init_xrm PARM((void));
|
||
+static void init_xrm_fonts PARM((void));
|
||
+static void init_xrm_tab PARM((void));
|
||
+#ifndef HAVE_STRDUP
|
||
+static char *strdup PARM((char *));
|
||
+#endif
|
||
+
|
||
+static char *default_fonts[] = { /* default for xrm_fonts */
|
||
+ "-sony-fixed-medium-r-normal--16-*-*-*-*-*-iso8859-1",
|
||
+ "-jis-fixed-medium-r-normal--16-*-*-*-*-*-jisx0208.1983-0",
|
||
+};
|
||
+static int xrm_nfonts;
|
||
+static char **xrm_fonts;
|
||
+
|
||
+static struct context *context; /* current context */
|
||
+
|
||
+struct ml_text *ml_draw_text(ctx, string, len)
|
||
+ struct context *ctx;
|
||
+ char *string;
|
||
+ int len;
|
||
+{
|
||
+ unsigned char *str = (unsigned char *) string;
|
||
+ unsigned char *estr = str + len;
|
||
+
|
||
+ context = ctx;
|
||
+
|
||
+ if(ascii == NULL){
|
||
+ fputs("ml_draw_text: call ml_set_charsets, first.\n", stderr);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ if(!str)
|
||
+ return &context->text;
|
||
+
|
||
+ WaitCursor();
|
||
+
|
||
+ if (context->text.maxlines != 0) {
|
||
+ struct ml_text *tp = &context->text;
|
||
+ struct ml_line *lp;
|
||
+ int i;
|
||
+ for (i = tp->nlines, lp = tp->lines; i > 0; i--, lp++) {
|
||
+ if (lp->maxitems != 0)
|
||
+ free((char *) lp->items);
|
||
+ }
|
||
+ free((char *) tp->lines);
|
||
+ tp->maxlines = tp->nlines = 0;
|
||
+ }
|
||
+ if (context->cbuf != NULL)
|
||
+ free((char *) context->cbuf);
|
||
+ context->cbp = (unsigned char *) malloc((size_t) len * 8);/* all \xxx */
|
||
+ context->cbuf = context->cbp;
|
||
+ context->line = 0;
|
||
+ context->delta = 0;
|
||
+ context->ss = NULL;
|
||
+
|
||
+ while(str < estr){
|
||
+ if((*str & 0x80) == 0){ /* left half */
|
||
+ struct charset *cs = context->ss ? *context->ss : *context->gl;
|
||
+ unsigned char min_char, max_char;
|
||
+ if (cs != NULL) {
|
||
+ if(cs->noc == 94){
|
||
+ min_char = 0x21;
|
||
+ max_char = 0x7e;
|
||
+ }else{
|
||
+ min_char = 0x20;
|
||
+ max_char = 0x7f;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (cs == NULL)
|
||
+ put_unknown_char(*str++);
|
||
+ else if(*str < min_char || *str > max_char){ /* C1 */
|
||
+ switch(*str){
|
||
+ case ' ':
|
||
+ {
|
||
+ unsigned char *p = str + 1;
|
||
+ while (*p == ' ' && p < estr)
|
||
+ p++;
|
||
+ pack_string(ascii, str, (int) (p - str));
|
||
+ str = p;
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case '\t':
|
||
+ pack_string(ascii, str++, 0);
|
||
+ break;
|
||
+
|
||
+ case '\n':
|
||
+ switch (context->eol) {
|
||
+ case 0: /* unix type eol */
|
||
+ pack_string(ascii, str, 0);
|
||
+ WaitCursor();
|
||
+ str++;
|
||
+ break;
|
||
+ case 1: /* dos type eol */
|
||
+ case 2: /* mac type eol */
|
||
+ put_unknown_char('\n');
|
||
+ str++;
|
||
+ break;
|
||
+ case 3: /* any type eol */
|
||
+ pack_string(ascii, str++, 0);
|
||
+ while (*str == '\n' || *str == '\r')
|
||
+ str++;
|
||
+ WaitCursor();
|
||
+ break;
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case '\r':
|
||
+ switch (context->eol) {
|
||
+ case 0:
|
||
+ put_unknown_char('\r');
|
||
+ str++;
|
||
+ break;
|
||
+ case 1:
|
||
+ str++;
|
||
+ if (*str == '\n')
|
||
+ pack_string(ascii, str++, 0);
|
||
+ else
|
||
+ put_unknown_char('\r');
|
||
+ break;
|
||
+ case 2:
|
||
+ pack_string(ascii, str, 0);
|
||
+ WaitCursor();
|
||
+ str++;
|
||
+ break;
|
||
+ case 3:
|
||
+ pack_string(ascii, str++, 0);
|
||
+ while (*str == '\n' || *str == '\r')
|
||
+ str++;
|
||
+ WaitCursor();
|
||
+ break;
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case '\033':
|
||
+ {
|
||
+ unsigned char *p;
|
||
+ str++;
|
||
+ if((p = escape_sequence(str)) == str)
|
||
+ put_unknown_char('\033');
|
||
+ else
|
||
+ str = p;
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case CODE_SI:
|
||
+ case CODE_SO:
|
||
+ if (!context->lock_shift)
|
||
+ put_unknown_char((unsigned int) *str++);
|
||
+ else
|
||
+ locking_shift((unsigned int) *str++);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ put_unknown_char((unsigned int) *str++);
|
||
+ }
|
||
+ }else{ /* GL */
|
||
+ if (context->ss != NULL) {
|
||
+ pack_string(cs, str, 1);
|
||
+ str += cs->bpc;
|
||
+ context->ss = NULL;
|
||
+ } else {
|
||
+ int n;
|
||
+
|
||
+ if (cs->bpc == 1) {
|
||
+ unsigned char *p = str;
|
||
+ for (n = 0; p < estr; n++) {
|
||
+ if (*p < min_char || *p > max_char)
|
||
+ break;
|
||
+ p++;
|
||
+ }
|
||
+ pack_string(cs, str, n);
|
||
+ str = p;
|
||
+ } else {
|
||
+ unsigned char *p = str;
|
||
+ for (n = 0; p < estr - 1; n++) {
|
||
+ if (*p < min_char || *p > max_char ||
|
||
+ *(p + 1) < min_char || *(p + 1) > max_char)
|
||
+ break;
|
||
+ p += 2;
|
||
+ }
|
||
+ if (n > 0)
|
||
+ pack_string(cs, str, n);
|
||
+ else
|
||
+ put_unknown_char(*p++);
|
||
+ str = p;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }else{ /* right half */
|
||
+ struct charset *cs = context->ss ? *context->ss : *context->gr;
|
||
+ unsigned char min_char, max_char;
|
||
+ if (cs != NULL) {
|
||
+ if(cs->noc == 94){
|
||
+ min_char = 0xa1;
|
||
+ max_char = 0xfe;
|
||
+ }else{
|
||
+ min_char = 0xa0;
|
||
+ max_char = 0xff;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (cs == NULL)
|
||
+ put_unknown_char(*str++);
|
||
+ else if(*str < min_char || *str > max_char){ /* C2 */
|
||
+ unsigned char c = *str++;
|
||
+ switch(c){
|
||
+ case CODE_SS2:
|
||
+ case CODE_SS3:
|
||
+ single_shift((unsigned CHAR) c);
|
||
+ break;
|
||
+ default:
|
||
+ put_unknown_char(c);
|
||
+ }
|
||
+ }else{ /* GR */
|
||
+ if (context->ss != NULL) {
|
||
+ pack_string(cs, str, 1);
|
||
+ str += cs->bpc;
|
||
+ context->ss = NULL;
|
||
+ } else {
|
||
+ int n;
|
||
+
|
||
+ if (cs->bpc == 1) {
|
||
+ unsigned char *p = str;
|
||
+ for (n = 0; p < estr; n++) {
|
||
+ if (*p < min_char || *p > max_char)
|
||
+ break;
|
||
+ p++;
|
||
+ }
|
||
+ pack_string(cs, str, n);
|
||
+ str = p;
|
||
+ } else {
|
||
+ unsigned char *p = str;
|
||
+ for (n = 0; p < estr - 1; n++) {
|
||
+ if (*p < min_char || *p > max_char ||
|
||
+ *(p + 1) < min_char || *(p + 1) > max_char)
|
||
+ break;
|
||
+ p += 2;
|
||
+ }
|
||
+ if (n > 0)
|
||
+ pack_string(cs, str, n);
|
||
+ else
|
||
+ put_unknown_char(*p++);
|
||
+ str = p;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ {
|
||
+ struct ml_text *tp = &context->text;
|
||
+ struct ml_line *lp;
|
||
+ int i;
|
||
+
|
||
+ tp->width = 0;
|
||
+ tp->height = 0;
|
||
+ for (lp = tp->lines, i = tp->nlines; i > 0; lp++, i--) {
|
||
+ if (lp->nitems == 0) {
|
||
+ lp->ascent = ascii->fs->ascent;
|
||
+ lp->descent = ascii->fs->descent;
|
||
+ }
|
||
+ if (tp->width < lp->width)
|
||
+ tp->width = lp->width;
|
||
+ tp->height += lp->ascent + lp->descent;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ SetCursors(-1);
|
||
+ return &context->text;
|
||
+}
|
||
+
|
||
+static unsigned char *escape_sequence(str)
|
||
+ unsigned char *str;
|
||
+{
|
||
+ unsigned char *p;
|
||
+ switch(*str){
|
||
+ case '$':
|
||
+ case '(': case ')': case '*': case '+':
|
||
+ case '-': case '.': case '/': case ',':
|
||
+ if((p = designator_sequence(str)) == NULL)
|
||
+ return str;
|
||
+ return p;
|
||
+ case 'n': case 'o': case '~': case '}': case '|':
|
||
+ if (!context->lock_shift)
|
||
+ return str;
|
||
+ locking_shift(*str);
|
||
+ return str + 1;
|
||
+ case 'N': case 'O':
|
||
+ single_shift(*str);
|
||
+ return str + 1;
|
||
+ }
|
||
+ return str;
|
||
+
|
||
+}
|
||
+
|
||
+static unsigned char *designator_sequence(str)
|
||
+ unsigned char *str;
|
||
+{
|
||
+ unsigned char *p = str;
|
||
+ int noc, bpc, n_g, shortened;
|
||
+ unsigned char des;
|
||
+ struct charset *cs;
|
||
+
|
||
+ if(*p == '$'){
|
||
+ bpc = 2;
|
||
+ p++;
|
||
+ }else
|
||
+ bpc = 1;
|
||
+
|
||
+ switch(*p++){
|
||
+ case '(': noc = 94; n_g = 0; des = *p++; shortened = 0; break;
|
||
+ case ')': noc = 94; n_g = 1; des = *p++; shortened = 0; break;
|
||
+ case '*': noc = 94; n_g = 2; des = *p++; shortened = 0; break;
|
||
+ case '+': noc = 94; n_g = 3; des = *p++; shortened = 0; break;
|
||
+#ifdef USE_MULE_EXTENSION
|
||
+ case ',': noc = 96; n_g = 0; des = *p++; shortened = 0; break;
|
||
+#endif
|
||
+ case '-': noc = 96; n_g = 1; des = *p++; shortened = 0; break;
|
||
+ case '.': noc = 96; n_g = 2; des = *p++; shortened = 0; break;
|
||
+ case '/': noc = 96; n_g = 3; des = *p++; shortened = 0; break;
|
||
+ case '@': noc = 94; n_g = 0; des = 'B'; shortened = 0; break;
|
||
+ case 'A': noc = 94; n_g = 0; des = 'A'; shortened = 1; break;
|
||
+ case 'B': noc = 94; n_g = 0; des = 'B'; shortened = 1; break;
|
||
+ default: return NULL;
|
||
+ }
|
||
+ if (!context->short_form && shortened)
|
||
+ return NULL;
|
||
+
|
||
+ if((cs = search_charset(bpc, noc, des)) == NULL){
|
||
+ if(DEBUG){
|
||
+ fprintf(stderr, "designator_sequence: (%d,%d,%c) not found.\n",
|
||
+ bpc, noc, des);
|
||
+ }
|
||
+ return NULL;
|
||
+ }
|
||
+ if (!context->valid[n_g])
|
||
+ return NULL;
|
||
+ context->g[n_g] = cs;
|
||
+ if(DEBUG){
|
||
+ fprintf(stderr,
|
||
+ "designator_sequence: G%d is `%s'.\n", n_g, cs->registry);
|
||
+ }
|
||
+ return p;
|
||
+}
|
||
+
|
||
+static void locking_shift(c)
|
||
+ unsigned CHAR c;
|
||
+{
|
||
+ switch((unsigned char) c){
|
||
+ case CODE_SI: context->gl = &context->g[0]; break;
|
||
+ case CODE_SO: context->gl = &context->g[1]; break;
|
||
+ case 'n': context->gl = &context->g[2]; break;
|
||
+ case 'o': context->gl = &context->g[3]; break;
|
||
+ case '~': context->gr = &context->g[1]; break;
|
||
+ case '}': context->gr = &context->g[2]; break;
|
||
+ case '|': context->gr = &context->g[3]; break;
|
||
+ }
|
||
+ if(DEBUG){
|
||
+ fprintf(stderr, "locking_shift: (%d,%d).\n",
|
||
+ (int)(context->gl - context->g),
|
||
+ (int)(context->gr - context->g));
|
||
+ }
|
||
+}
|
||
+
|
||
+static void single_shift(c)
|
||
+ unsigned CHAR c;
|
||
+{
|
||
+ switch((unsigned char) c){
|
||
+ case CODE_SS2: context->ss = &context->g[2]; break;
|
||
+ case CODE_SS3: context->ss = &context->g[3]; break;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+static void put_unknown_char(chr)
|
||
+ unsigned CHAR chr;
|
||
+{
|
||
+ unsigned char c = chr;
|
||
+
|
||
+ if(c < 0x20){
|
||
+ unsigned char buf[2];
|
||
+ buf[0] = '^';
|
||
+ buf[1] = c + 0x40;
|
||
+ pack_string(ascii, buf, 2);
|
||
+ }else{
|
||
+ unsigned char buf[4];
|
||
+ buf[0] = '\\';
|
||
+ buf[1] = ((c >> 6) & 07) + '0';
|
||
+ buf[2] = ((c >> 3) & 07) + '0';
|
||
+ buf[3] = ((c ) & 07) + '0';
|
||
+ pack_string(ascii, buf, 4);
|
||
+ }
|
||
+}
|
||
+
|
||
+struct context *ml_create_context(s)
|
||
+ Screen *s;
|
||
+{
|
||
+ context = (struct context *) malloc(sizeof *context);
|
||
+
|
||
+ context->g[0] = NULL;
|
||
+ context->g[1] = NULL;
|
||
+ context->g[2] = NULL;
|
||
+ context->g[3] = NULL;
|
||
+ context->gl = NULL;
|
||
+ context->gr = NULL;
|
||
+ context->ss = NULL;
|
||
+
|
||
+ context->cbuf = NULL;
|
||
+ context->text.maxlines = context->text.nlines = 0;
|
||
+ context->line = 0;
|
||
+ context->delta = 0;
|
||
+ context->toolong = 0;
|
||
+
|
||
+ DPY = DisplayOfScreen(s);
|
||
+ SCR = s;
|
||
+ ROOT_WIN = RootWindowOfScreen(s);
|
||
+
|
||
+ return context;
|
||
+}
|
||
+
|
||
+
|
||
+int ml_set_charsets(ctx, sys)
|
||
+ struct context *ctx;
|
||
+ struct coding_system *sys;
|
||
+{
|
||
+ int retval = 0;
|
||
+ int i;
|
||
+
|
||
+ context = ctx;
|
||
+
|
||
+ if(ascii == NULL){
|
||
+ init_xrm();
|
||
+ if((ascii = search_charset(1, 94, 'B')) == NULL){
|
||
+ fputs("ml_set_charsets: ascii charset not found.\n", stderr);
|
||
+ Quit(1);
|
||
+ }
|
||
+ if (ascii->fs == NULL) {
|
||
+ fputs("ml_set_charsets: iso8859-1 font not found.\n", stderr);
|
||
+ Quit(1);
|
||
+ }
|
||
+ }
|
||
+ for(i = 0; i < 4; i++){
|
||
+ switch(sys->design[i].bpc){
|
||
+ case -1: /* make G[i] invalid */
|
||
+ context->valid[i] = 0;
|
||
+ break;
|
||
+
|
||
+ case 0: /* don't change */
|
||
+ break;
|
||
+
|
||
+ case 1: case 2: /* change it */
|
||
+ if((context->g[i] = search_charset(sys->design[i].bpc,
|
||
+ sys->design[i].noc,
|
||
+ sys->design[i].des)) == NULL){
|
||
+ fputs("ml_set_charsets: ", stderr);
|
||
+ fprintf(stderr, "(%d,%d,%c) is specified as G%d, ",
|
||
+ sys->design[i].bpc, sys->design[i].noc,
|
||
+ sys->design[i].des, i);
|
||
+ fputs("but not found. using `iso8859-1'.\n", stderr);
|
||
+ context->g[i] = ascii;
|
||
+ retval++;
|
||
+ }
|
||
+ context->valid[i] = 1;
|
||
+ break;
|
||
+
|
||
+ default: /* error */
|
||
+ fprintf(stderr,"ml_set_charsets: bad arguments of G%d. ", i);
|
||
+ fputs("using `iso8859-1'.\n", stderr);
|
||
+ context->g[i] = ascii;
|
||
+ retval++;
|
||
+ }
|
||
+ }
|
||
+ if((unsigned int) sys->gl < 4)
|
||
+ context->gl = &context->g[sys->gl];
|
||
+ else{
|
||
+ fprintf(stderr, "ml_set_charsets: bad number as GL. using G0.\n");
|
||
+ context->gl = &context->g[0];
|
||
+ }
|
||
+ if((unsigned int) sys->gr < 4)
|
||
+ context->gr = &context->g[sys->gr];
|
||
+ else{
|
||
+ fprintf(stderr, "ml_set_charsets: bad number as GR. using G0.\n");
|
||
+ context->gr = &context->g[0];
|
||
+ }
|
||
+ context->eol = sys->eol;
|
||
+ context->short_form = sys->short_form;
|
||
+ context->lock_shift = sys->lock_shift;
|
||
+ return retval;
|
||
+}
|
||
+
|
||
+static struct charset *search_charset(bpc, noc, des)
|
||
+ int bpc, noc;
|
||
+ int des;
|
||
+{
|
||
+ struct charset *cset;
|
||
+ for(cset = charset; cset->bpc != 0; cset++){
|
||
+ if(cset->bpc == bpc &&
|
||
+ cset->noc == noc &&
|
||
+ cset->designator == (char) des){
|
||
+ if(!cset->loaded){
|
||
+#if 0
|
||
+ int i, l;
|
||
+ l = strlen(cset->registry);
|
||
+ for (i = 0; i < xrm_nfonts; i++) {
|
||
+ int li = strlen(xrm_fonts[i]);
|
||
+ if (li > l) {
|
||
+ if (xrm_fonts[i][li - l - 1] == '-' &&
|
||
+ strcmp(xrm_fonts[i] + li - l,
|
||
+ cset->registry) == 0) {
|
||
+ if ((cset->fs = XLoadQueryFont(DPY, xrm_fonts[i]))
|
||
+ != NULL) {
|
||
+ if (DEBUG) {
|
||
+ fprintf(stderr, "%s for %s\n",
|
||
+ xrm_fonts[i], cset->registry);
|
||
+ }
|
||
+ cset->fontname = xrm_fonts[i];
|
||
+ break;
|
||
+ } else
|
||
+ SetISTR(ISTR_WARNING,
|
||
+ "%s: font not found.", xrm_fonts[i]);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+#else
|
||
+ int i, l;
|
||
+ l = strlen(cset->registry);
|
||
+ for (i = 0; i < xrm_nfonts && cset->fs == NULL; i++) {
|
||
+ int j, nfnts = 0;
|
||
+ char **fnts = XListFonts(DPY, xrm_fonts[i],
|
||
+ 65535, &nfnts);
|
||
+ for (j = 0 ; j < nfnts; j++) {
|
||
+ int ll = strlen(fnts[j]);
|
||
+ if (*(fnts[j] + ll - l - 1) == '-' &&
|
||
+ strcmp(fnts[j] + ll - l, cset->registry)== 0) {
|
||
+ if ((cset->fs = XLoadQueryFont(DPY, fnts[j]))
|
||
+ != NULL) {
|
||
+ if (DEBUG) {
|
||
+ fprintf(stderr, "%s for %s\n",
|
||
+ fnts[j], cset->registry);
|
||
+ }
|
||
+ cset->fontname = strdup(fnts[j]);
|
||
+ break;
|
||
+ } else
|
||
+ SetISTR(ISTR_WARNING,
|
||
+ "%s: font not found", fnts[j]);
|
||
+ }
|
||
+ }
|
||
+ if (fnts != NULL)
|
||
+ XFreeFontNames(fnts);
|
||
+ }
|
||
+#endif
|
||
+ if(cset->fs == NULL){
|
||
+ SetISTR(ISTR_WARNING,
|
||
+ "font for %s not found.\nusing ascii font.",
|
||
+ cset->registry);
|
||
+ if (ascii != NULL)
|
||
+ cset->fs = ascii->fs;
|
||
+ }
|
||
+
|
||
+ cset->loaded = 1;
|
||
+ }
|
||
+ return cset;
|
||
+ }
|
||
+ }
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static void pack_string(cs, str, len)
|
||
+ struct charset *cs;
|
||
+ unsigned char *str;
|
||
+ int len; /* number of chars(not bytes) */
|
||
+{
|
||
+ struct ml_text *mt = &context->text;
|
||
+ struct ml_line *lp;
|
||
+ XTextItem16 *ip;
|
||
+
|
||
+ if (context->line == mt->maxlines) {
|
||
+ int oldmax = mt->maxlines;
|
||
+ if (mt->maxlines < 1)
|
||
+ mt->maxlines = 1;
|
||
+ else
|
||
+ mt->maxlines = 2 * mt->maxlines;
|
||
+ if (oldmax == 0)
|
||
+ mt->lines = (struct ml_line *)
|
||
+ malloc(sizeof(struct ml_line) * mt->maxlines);
|
||
+ else {
|
||
+ mt->lines = (struct ml_line *)
|
||
+ realloc(mt->lines,
|
||
+ sizeof(struct ml_line) * mt->maxlines);
|
||
+ }
|
||
+ }
|
||
+ lp = &mt->lines[context->line];
|
||
+ if (mt->nlines == context->line) {
|
||
+ mt->nlines++;
|
||
+ lp->maxitems = 0;
|
||
+ lp->nitems = 0;
|
||
+ lp->width = 0;
|
||
+ lp->ascent = lp->descent = 0;
|
||
+ }
|
||
+
|
||
+ if (len == 0) {
|
||
+ switch (*str) {
|
||
+ case '\n':
|
||
+ context->line++;
|
||
+ context->delta = 0;
|
||
+ context->toolong = 0;
|
||
+ break;
|
||
+ case '\t':
|
||
+ {
|
||
+ int nx, x = lp->width + context->delta;
|
||
+ nx = (x + ml_tab_width) / ml_tab_width * ml_tab_width;
|
||
+ context->delta += nx - x;
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ if (context->toolong)
|
||
+ return;
|
||
+ if (lp->width > 30000) {
|
||
+ context->toolong = 1;
|
||
+ cs = ascii;
|
||
+ str = (unsigned char *) "...";
|
||
+ len = 3;
|
||
+ }
|
||
+
|
||
+ if (lp->nitems == lp->maxitems) {
|
||
+ int oldmax = lp->maxitems;
|
||
+ if (lp->maxitems < 1)
|
||
+ lp->maxitems = 1;
|
||
+ else
|
||
+ lp->maxitems = 2 * lp->maxitems;
|
||
+ if (oldmax == 0)
|
||
+ lp->items = (XTextItem16 *)
|
||
+ malloc(sizeof(XTextItem16) * lp->maxitems);
|
||
+ else
|
||
+ lp->items = (XTextItem16 *)
|
||
+ realloc(lp->items,
|
||
+ sizeof(XTextItem16) * lp->maxitems);
|
||
+ }
|
||
+ ip = &lp->items[lp->nitems++];
|
||
+ ip->chars = (XChar2b *) context->cbp;
|
||
+ ip->nchars = len;
|
||
+ ip->delta = context->delta;
|
||
+ ip->font = cs->fs->fid;
|
||
+ context->cbp += 2 * len;
|
||
+ context->delta = 0;
|
||
+
|
||
+ if (cs->bpc == 1) {
|
||
+ XChar2b *p;
|
||
+ unsigned char b7 = cs->bit7 ? 0x80 : 0;
|
||
+ int i;
|
||
+ for (i = len, p = ip->chars; i > 0; i--, p++) {
|
||
+ p->byte1 = '\0';
|
||
+ p->byte2 = (*str++ & 0x7f) | b7;
|
||
+ }
|
||
+ } else {
|
||
+ XChar2b *p;
|
||
+ unsigned char b7 = cs->bit7 ? 0x80 : 0;
|
||
+ int i;
|
||
+ for (i = len, p = ip->chars; i > 0; i--, p++) {
|
||
+ p->byte1 = (*str++ & 0x7f) | b7;
|
||
+ p->byte2 = (*str++ & 0x7f) | b7;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ lp->width += XTextWidth16(cs->fs, ip->chars, ip->nchars);
|
||
+ if (lp->ascent < cs->fs->ascent)
|
||
+ lp->ascent = cs->fs->ascent;
|
||
+ if (lp->descent < cs->fs->descent)
|
||
+ lp->descent = cs->fs->descent;
|
||
+}
|
||
+
|
||
+void get_monofont_size(wide, high)
|
||
+ int *wide, *high;
|
||
+{
|
||
+ if (ascii == NULL) {
|
||
+ fputs("ml_draw_text: call ml_set_charsets, first.\n", stderr);
|
||
+ return;
|
||
+ }
|
||
+ *wide = ascii->fs->max_bounds.width;
|
||
+ *high = ascii->fs->ascent + ascii->fs->descent;
|
||
+}
|
||
+
|
||
+static void init_xrm()
|
||
+{
|
||
+ init_xrm_fonts();
|
||
+ init_xrm_tab();
|
||
+}
|
||
+
|
||
+static void init_xrm_fonts()
|
||
+{
|
||
+ char *p, *fns = XGetDefault(theDisp, "xv", "fontSet");
|
||
+ int n;
|
||
+ if (fns == NULL) {
|
||
+ xrm_fonts = default_fonts;
|
||
+ xrm_nfonts = sizeof default_fonts / sizeof *default_fonts;
|
||
+ return;
|
||
+ }
|
||
+ while(*fns == ' ' || *fns == '\t')
|
||
+ fns++;
|
||
+ if (*fns == '\0') {
|
||
+ xrm_fonts = default_fonts;
|
||
+ xrm_nfonts = sizeof default_fonts / sizeof *default_fonts;
|
||
+ return;
|
||
+ }
|
||
+ fns = strdup(fns);
|
||
+
|
||
+ n = 1;
|
||
+ for (p = fns; *p != '\0'; p++) {
|
||
+ if (*p == ',')
|
||
+ n++;
|
||
+ }
|
||
+ xrm_nfonts = n;
|
||
+ xrm_fonts = (char **) malloc(sizeof (char *) * xrm_nfonts);
|
||
+ for (n = 0, p = fns; n < xrm_nfonts && *p != '\0'; ) {
|
||
+ while (*p == ' ' || *p == '\t')
|
||
+ p++;
|
||
+ xrm_fonts[n++] = p;
|
||
+ while (1) {
|
||
+ char *q;
|
||
+ while (*p != ' ' && *p != '\t' && *p != ',' && *p != '\0')
|
||
+ p++;
|
||
+ q = p;
|
||
+ while (*q == ' ' || *q == '\t')
|
||
+ q++;
|
||
+ if (*q == ',' || *q == '\0') {
|
||
+ *p = '\0';
|
||
+ p = q + 1;
|
||
+ break;
|
||
+ } else
|
||
+ p = q;
|
||
+ }
|
||
+ }
|
||
+ for ( ; n < xrm_nfonts; n++)
|
||
+ xrm_fonts[n] = "";
|
||
+}
|
||
+
|
||
+static void init_xrm_tab()
|
||
+{
|
||
+ char *ts = XGetDefault(theDisp, "xv", "tabWidth");
|
||
+ unsigned short tab;
|
||
+ if (ts == NULL)
|
||
+ tab = 64;
|
||
+ else {
|
||
+ char *ep;
|
||
+ long t;
|
||
+ int bad = 0;
|
||
+ t = strtol(ts, &ep, 0);
|
||
+ tab = (unsigned short) t;
|
||
+ if (ep != NULL) {
|
||
+ while (*ep == ' ' && *ep == '\t')
|
||
+ ep++;
|
||
+ if (*ep != '\0')
|
||
+ bad = 1;
|
||
+ }
|
||
+ if (tab != (long) (unsigned long) t)
|
||
+ bad = 1;
|
||
+ if (bad) {
|
||
+ SetISTR(ISTR_WARNING, "bad tab width.");
|
||
+ tab = 64;
|
||
+ }
|
||
+ }
|
||
+ ml_tab_width = tab;
|
||
+}
|
||
+
|
||
+
|
||
+#ifndef HAVE_STRDUP
|
||
+static char *strdup(str)
|
||
+ char *str;
|
||
+{
|
||
+ return strcpy(malloc(strlen(str) + 1), str);
|
||
+}
|
||
+#endif
|
||
+
|
||
+char *lookup_registry(d, b7)
|
||
+ struct design d;
|
||
+ int *b7;
|
||
+{
|
||
+ int i;
|
||
+ for (i = 0; i < NR_CHARSETS; i++) {
|
||
+ if (charset[i].bpc == d.bpc && charset[i].noc == d.noc &&
|
||
+ charset[i].designator == d.des) {
|
||
+ *b7 = charset[i].bit7;
|
||
+ return charset[i].registry;
|
||
+ }
|
||
+ }
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+struct design lookup_design(registry, b7)
|
||
+ char *registry;
|
||
+ int b7;
|
||
+{
|
||
+ struct design d;
|
||
+ int i;
|
||
+ d.bpc = 0;
|
||
+ d.noc = 0;
|
||
+ d.des = '\0';
|
||
+ for (i = 0; i < NR_CHARSETS; i++) {
|
||
+ if (strcmp(charset[i].registry, registry) == 0 &&
|
||
+ charset[i].bit7 == b7) {
|
||
+ d.bpc = charset[i].bpc;
|
||
+ d.noc = charset[i].noc;
|
||
+ d.des = charset[i].designator;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ return d;
|
||
+}
|
||
+
|
||
+char *sjis_to_jis(orig, len, newlen)
|
||
+ char *orig;
|
||
+ int len, *newlen;
|
||
+{
|
||
+ unsigned char *new;
|
||
+ unsigned char *p, *q, *endp;
|
||
+ if (len == 0) {
|
||
+ *newlen = 0;
|
||
+ return (char *) malloc((size_t) 1);
|
||
+ }
|
||
+ new = (unsigned char *) malloc((size_t) len * 4); /* big enough */
|
||
+ for (p = (unsigned char *) orig, endp = p + len, q = new; p < endp; ) {
|
||
+ if ((*p & 0x80) == 0) /* 1 byte char */
|
||
+ *q++ = *p++;
|
||
+ else if (*p >= 0x81 && *p <= 0x9f) { /* kanji 1st byte */
|
||
+ unsigned char c1 = *p++;
|
||
+ unsigned char c2 = *p++;
|
||
+ if (c2 < 0x40 || c2 > 0xfc) { /* bad 2nd byte */
|
||
+ *q++ = CODE_SS2;
|
||
+ *q++ = c1;
|
||
+ *q++ = CODE_SS2;
|
||
+ *q++ = c2;
|
||
+ } else { /* right 2nd byte */
|
||
+ if (c2 <= 0x9e) {
|
||
+ if (c2 > 0x7f)
|
||
+ c2--;
|
||
+ c1 = (c1 - 0x81) * 2 + 1 + 0xa0;
|
||
+ c2 = (c2 - 0x40) + 1 + 0xa0;
|
||
+ } else {
|
||
+ c1 = (c1 - 0x81) * 2 + 2 + 0xa0;
|
||
+ c2 = (c2 - 0x9f) + 1 + 0xa0;
|
||
+ }
|
||
+ *q++ = c1;
|
||
+ *q++ = c2;
|
||
+ }
|
||
+ } else if (*p >= 0xe0 && *p <= 0xef) { /* kanji 1st byte */
|
||
+ unsigned char c1 = *p++;
|
||
+ unsigned char c2 = *p++;
|
||
+ if (c2 < 0x40 || c2 > 0xfc) { /* bad 2nd byte */
|
||
+ *q++ = CODE_SS2;
|
||
+ *q++ = c1;
|
||
+ *q++ = CODE_SS2;
|
||
+ *q++ = c2;
|
||
+ } else { /* right 2nd byte */
|
||
+ if (c2 <= 0x9e) {
|
||
+ c1 = (c1 - 0xe0) * 2 + 63 + 0xa0;
|
||
+ c2 = (c2 - 0x40) + 1 + 0xa0;
|
||
+ } else {
|
||
+ c1 = (c1 - 0xe0) * 2 + 64 + 0xa0;
|
||
+ c2 = (c2 - 0x9f) + 1 + 0xa0;
|
||
+ }
|
||
+ *q++ = c1;
|
||
+ *q++ = c2;
|
||
+ }
|
||
+ } else { /* katakana or something */
|
||
+ *q++ = CODE_SS2;
|
||
+ *q++ = *p++;
|
||
+ }
|
||
+ }
|
||
+ *newlen = q - new;
|
||
+
|
||
+ return (char *) realloc(new, (size_t) *newlen);
|
||
+}
|
||
+
|
||
+#endif /* TV_MULTILINGUAL */
|
||
diff -u -r --new-file xv-3.10a.orig/xvml.h xv-3.10a/xvml.h
|
||
--- xv-3.10a.orig/xvml.h 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvml.h 2005-04-18 00:57:45.000000000 -0500
|
||
@@ -0,0 +1,96 @@
|
||
+#ifndef MLVIEW_H
|
||
+#define MLVIEW_H
|
||
+
|
||
+/*
|
||
+ * What is this?
|
||
+ *
|
||
+ * It is a package to show multi-lingual text.
|
||
+ *
|
||
+ * How to use?
|
||
+ *
|
||
+ * 1. Call ml_set_screen(Screen *scr);
|
||
+ * Tell this package the screen you use.
|
||
+ *
|
||
+ * 2. Call ml_set_charsets(struct char_spec spec[4], int gl, int gr);
|
||
+ * Tell this package the initial charsets.
|
||
+ * Gn is set to the charset specified by spec[n], respectively.
|
||
+ * GL and GR are set to G[gl] and G[gr], respectively.
|
||
+ * If first call, iso8859-1 font is loaded.
|
||
+ *
|
||
+ * 3. Call ml_draw_text(char *string);
|
||
+ * It Creates a bitmap, and returns it to you.
|
||
+ * If something goes wrong, it returns None.
|
||
+ * DON'T free the returned pixmaps!!
|
||
+ *
|
||
+ * BUGS:
|
||
+ * - Amharic and Tigrigna characters are strange.
|
||
+ * - Big5 is not supported.
|
||
+ * - Reverse direction is not supported.
|
||
+ * - Composing is not supported.
|
||
+ * - Cantonese can't be shown.
|
||
+ * - Texts which have many lines are buggy.
|
||
+ *
|
||
+ * NOTE:
|
||
+ * - Shifted JIS and Shifted GB must be converted to iso2022 in advance.
|
||
+ *
|
||
+ * Example of parameters to ml_set_charsets:
|
||
+ * - EUC-Japan
|
||
+ * spec = { {1, 94, 'B'}, G0 is US-ASCII
|
||
+ * {2, 94, 'B'}, G1 is JIS X0208
|
||
+ * {1, 94, 'J'}, G2 is (right-half of)JIS X0201
|
||
+ * {2, 94, 'D'} }; G3 is JIS X0212
|
||
+ * gl = 0; GL is G0
|
||
+ * gr = 1; GR is G1
|
||
+ *
|
||
+ * - Compound Text
|
||
+ * spec = { {1, 94, 'B'}, G0 is US-ASCII
|
||
+ * {1, 96, 'A'}, G1 is Latin-1
|
||
+ * {1, 94, 'B'}, G2 is US-ASCII (maybe unused)
|
||
+ * {1, 94, 'B'} }; G3 is US-ASCII (maybe unused)
|
||
+ * gl = 0; GL is G0
|
||
+ * gr = 1; GR is G1
|
||
+ *
|
||
+ * - Korean Mail
|
||
+ * spec = { {1, 94, 'B'}, G0 is US-ASCII
|
||
+ * {2, 94, 'C'}, G1 is KSC5601
|
||
+ * {1, 94, 'B'}, G2 is US-ASCII (maybe unused)
|
||
+ * {1, 94, 'B'} }; G3 is US-ASCII (maybe unused)
|
||
+ * gl = 0; GL is G0
|
||
+ * gl = 1; GR is G1
|
||
+ */
|
||
+
|
||
+struct coding_system {
|
||
+ struct design {
|
||
+ int bpc; /* byte per char if 1 or 2,
|
||
+ don't touch if 0, or
|
||
+ don't use if -1.*/
|
||
+ int noc; /* number of chars (94 or 96) */
|
||
+ char des; /* designator ('A', 'B', ...) */
|
||
+ } design[4];
|
||
+ int gl, gr;
|
||
+ int eol;
|
||
+ int short_form;
|
||
+ int lock_shift;
|
||
+};
|
||
+
|
||
+struct ml_text {
|
||
+ int maxlines, nlines;
|
||
+ struct ml_line {
|
||
+ int maxitems, nitems;
|
||
+ int width, ascent, descent;
|
||
+ XTextItem16 *items;
|
||
+ } *lines;
|
||
+ int width, height;
|
||
+};
|
||
+
|
||
+struct context;
|
||
+struct ml_text *ml_draw_text PARM((struct context *, char *, int));
|
||
+struct context *ml_create_context PARM((Screen *));
|
||
+int ml_set_charsets PARM((struct context *,
|
||
+ struct coding_system *));
|
||
+void get_monofont_size PARM((int *, int *));
|
||
+char *sjis_to_jis PARM((char *, int, int *));
|
||
+char *lookup_registry PARM((struct design, int *));
|
||
+struct design lookup_design PARM((char *, int));
|
||
+
|
||
+#endif
|
||
diff -u -r --new-file xv-3.10a.orig/xvpcd.c xv-3.10a/xvpcd.c
|
||
--- xv-3.10a.orig/xvpcd.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvpcd.c 2007-05-13 20:02:13.000000000 -0500
|
||
@@ -0,0 +1,1311 @@
|
||
+/*
|
||
+ * xvpcd.c - load routine for 'PhotoCD' format pictures
|
||
+ *
|
||
+ * LoadPCD(fname, pinfo, size) - loads a PhotoCD file
|
||
+ *
|
||
+ * This routine will popup a choice of which of the 5 available resolutions
|
||
+ * the user wants to choose, then load it as a 24 bit image.
|
||
+ *
|
||
+ * Copyright 1993 David Clunie, Melbourne, Australia.
|
||
+ *
|
||
+ * The outline of this is shamelessly derived from xvpbm.c to read the
|
||
+ * file, and xvtiffwr.c to handle the popup window and X stuff (X never
|
||
+ * has been my forte !), and the PhotoCD format information (though not
|
||
+ * the code) was found in Hadmut Danisch's (danisch@ira.uka.de) hpcdtoppm
|
||
+ * program in which he has reverse engineered the format by studying
|
||
+ * hex dumps of PhotoCDs ! After all who can afford the Kodak developer's
|
||
+ * kit, which none of us have seen yet ? Am I even allowed to mention these
|
||
+ * words (Kodak, PhotoCD) ? I presume they are registered trade marks.
|
||
+ *
|
||
+ * PS. I have no idea how Halmut worked out the YCC <-> RGB conversion
|
||
+ * factors, but I have calculated them from his tables and the results
|
||
+ * look good enough to me.
|
||
+ *
|
||
+ * Added size parameter to allow the schnautzer to create thumnails
|
||
+ * without requesting the size every time.
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+
|
||
+#ifdef HAVE_PCD
|
||
+
|
||
+#include <memory.h>
|
||
+#ifndef alloca
|
||
+# include <alloca.h> /* "not in POSIX or SUSv3" according to Linux man page */
|
||
+#endif /* ...but required for Sun C compiler (alloca = macro) */
|
||
+
|
||
+#define TRACE 0
|
||
+#if TRACE
|
||
+# define trace(x) fprintf x
|
||
+#else
|
||
+# define trace(x)
|
||
+#endif
|
||
+
|
||
+/* Comments on error-handling:
|
||
+ A truncated file is not considered a Major Error. The file is loaded,
|
||
+ and the rest of the pic is filled with 0's.
|
||
+
|
||
+ Not being able to malloc is a Fatal Error. The program is aborted. */
|
||
+
|
||
+
|
||
+#ifdef __STDC__
|
||
+static void magnify(int, int, int, int, int, byte *);
|
||
+static int pcdError(const char *, const char *);
|
||
+static int gethuffdata(byte *, byte *, byte *, int, int);
|
||
+#else
|
||
+static void magnify();
|
||
+static int pcdError();
|
||
+static int gethuffdata();
|
||
+#endif
|
||
+
|
||
+#define wcurfactor 16 /* Call WaitCursor() every n rows */
|
||
+
|
||
+static int size; /* Set by window routines */
|
||
+static int leaveitup;/* Cleared by docmd() when OK or CANCEL pressed */
|
||
+static int goforit; /* Set to 1 if OK or 0 if CANCEL */
|
||
+static FILE *fp;
|
||
+static CBUTT lutCB;
|
||
+
|
||
+/*
|
||
+ * This "beyond 100%" table is taken from ImageMagick (gamma 2.2).
|
||
+ * Why there are 351 entries and not 346 as per Kodak documentation
|
||
+ * is a mystery.
|
||
+ */
|
||
+static double rscale = 1.00,
|
||
+ gscale = 1.00,
|
||
+ bscale = 1.00;
|
||
+
|
||
+static byte Y[351] = {
|
||
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||
+ 30, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||
+ 41, 42, 43, 45, 46, 47, 48, 49, 50, 51,
|
||
+ 52, 53, 54, 56, 57, 58, 59, 60, 61, 62,
|
||
+ 63, 64, 66, 67, 68, 69, 70, 71, 72, 73,
|
||
+ 74, 76, 77, 78, 79, 80, 81, 82, 83, 84,
|
||
+ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||
+ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
|
||
+ 107, 108, 110, 111, 112, 113, 114, 115, 116, 117,
|
||
+ 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
|
||
+ 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
|
||
+ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
|
||
+ 149, 150, 151, 152, 153, 154, 155, 156, 157, 158,
|
||
+ 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
|
||
+ 169, 170, 171, 172, 173, 174, 175, 176, 176, 177,
|
||
+ 178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
|
||
+ 188, 189, 190, 191, 192, 193, 193, 194, 195, 196,
|
||
+ 197, 198, 199, 200, 201, 201, 202, 203, 204, 205,
|
||
+ 206, 207, 207, 208, 209, 210, 211, 211, 212, 213,
|
||
+ 214, 215, 215, 216, 217, 218, 218, 219, 220, 221,
|
||
+ 221, 222, 223, 224, 224, 225, 226, 226, 227, 228,
|
||
+ 228, 229, 230, 230, 231, 232, 232, 233, 234, 234,
|
||
+ 235, 236, 236, 237, 237, 238, 238, 239, 240, 240,
|
||
+ 241, 241, 242, 242, 243, 243, 244, 244, 245, 245,
|
||
+ 245, 246, 246, 247, 247, 247, 248, 248, 248, 249,
|
||
+ 249, 249, 249, 250, 250, 250, 250, 251, 251, 251,
|
||
+ 251, 251, 252, 252, 252, 252, 252, 253, 253, 253,
|
||
+ 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
|
||
+ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
|
||
+ 254, 254, 254, 254, 254, 254, 254, 254, 254, 255,
|
||
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||
+ 255
|
||
+};
|
||
+
|
||
+/*******************************************/
|
||
+/* The size should be -1 for the popup to ask otherwise fast is assumed */
|
||
+/* returns '1' on success */
|
||
+/*******************************************/
|
||
+int
|
||
+LoadPCD(char *fname, PICINFO *pinfo, int theSize)
|
||
+{
|
||
+ long offset;
|
||
+ int mag;
|
||
+ int rotate;
|
||
+ byte header[3*0x800];
|
||
+ byte *pic24, *luma, *chroma1, *chroma2, *ptr, *lptr, *c1ptr, *c2ptr;
|
||
+ int w, h, npixels, bufsize;
|
||
+ int row, col;
|
||
+ int huffplanes;
|
||
+ const char *bname;
|
||
+
|
||
+ bname = BaseName(fname);
|
||
+ pinfo->pic = NULL;
|
||
+ pinfo->comment = NULL;
|
||
+
|
||
+
|
||
+ /*
|
||
+ * open the file
|
||
+ */
|
||
+ if((fp=fopen(fname,"r")) == NULL)
|
||
+ return pcdError(bname, "can't open file");
|
||
+
|
||
+ /*
|
||
+ * inspect the header
|
||
+ */
|
||
+ if(fread(&header[0], 1, sizeof(header), fp) != sizeof(header))
|
||
+ return pcdError(bname, "could not load PCD header");
|
||
+ if(strncmp((char *)&header[0x800], "PCD_", 4) != 0)
|
||
+ return pcdError(bname, "not a PCD file");
|
||
+ rotate = header[0x0E02] & 0x03;
|
||
+
|
||
+/* base/16
|
||
+ - plain data starts at sector 1+2+1=4
|
||
+ (numbered from 0, ie. the 5th sector)
|
||
+ - luma 192*128 = 24576 bytes (12 sectors)
|
||
+ + chroma1 96*64 = 6144 bytes (3 sectors)
|
||
+ + chroma2 96*64 = 6144 bytes (3 sectors)
|
||
+ = total 18 sectors
|
||
+
|
||
+ - NB. "Plain" data is interleaved - 2 luma rows 192 wide,
|
||
+ then 1 of each of the chroma rows 96 wide !
|
||
+
|
||
+ base/4
|
||
+ - plain data starts at sector 1+2+1+18+1=23
|
||
+ - luma 384*256 = 98304 bytes (48 sectors)
|
||
+ + chroma1 192*128 = 24576 bytes (12 sectors)
|
||
+ + chroma2 192*128 = 24576 bytes (12 sectors)
|
||
+ = total 72 sectors
|
||
+
|
||
+ - NB. "Plain" data is interleaved - 2 luma rows 384 wide,
|
||
+ then 1 of each of the chroma rows 192 wide !
|
||
+
|
||
+ base
|
||
+ - plain data starts at sector 1+2+1+18+1+72+1=96
|
||
+
|
||
+ - luma 768*512 = 393216 bytes (192 sectors)
|
||
+ + chroma1 384*256 = 98304 bytes (48 sectors)
|
||
+ + chroma2 384*256 = 98304 bytes (48 sectors)
|
||
+ = total 288 sectors
|
||
+
|
||
+ - NB. "Plain" data is interleaved - 2 luma rows 768 wide,
|
||
+ then 1 of each of the chroma rows 384 wide !
|
||
+
|
||
+ 4base
|
||
+ - plain data for base is read
|
||
+ - luma data interpolated *2
|
||
+ - chroma data interpolated *4
|
||
+
|
||
+ - cd_offset is 1+2+1+18+1+72+1+288=384
|
||
+ - at cd_offset+4 (388) is huffman table
|
||
+ - at cd_offset+5 (389) is 4base luma plane
|
||
+
|
||
+ (the sector at cd_offset+3 seems to contain 256 words each of
|
||
+ which is an offset presumably to the sector containing certain
|
||
+ rows ? rows/4 given 1024 possible rows. The rest of this sector
|
||
+ is filled with zeroes)
|
||
+
|
||
+
|
||
+ 16base
|
||
+ - plain data for base is read
|
||
+ - luma data interpolated *2
|
||
+ - chroma data interpolated *4
|
||
+
|
||
+ - cd_offset is 1+2+1+18+1+72+1+288=384
|
||
+ - at cd_offset+4 (388) is huffman table for 4 base
|
||
+ - at cd_offset+5 (389) is 4base luma plane
|
||
+ - luma plane interpolated *2
|
||
+
|
||
+ - cd_offset is set to current position (should be start of sector)
|
||
+ - at cd_offset+12 is huffman table for 16 base
|
||
+ - at cd_offset+14 is 16 base luma & 2 chroma planes which are read
|
||
+ (note that the luma plane comes first, with a sync pattern
|
||
+ announcing each row from 0 to 2047, then the two chroma planes
|
||
+ are interleaved by row, the row # being even from 0 to 2046, with
|
||
+ each row containing 1536 values, the chroma1 row coming first,
|
||
+ finally followed by a sync pattern with a row of 2048 announcing
|
||
+ the end (its plane seems to be set to 3, ie. chroma2)
|
||
+ - chroma planes interpolated *2
|
||
+
|
||
+ (the sector at cd_offset+10 & 11 seem to contain 1024 pairs of words
|
||
+ the first for luma and the second for chroma, each of
|
||
+ which is an offset presumably to the sector containing certain
|
||
+ rows ? rows/2 given 2048 possible rows)
|
||
+
|
||
+Not yet implemented:
|
||
+
|
||
+In order to do overskip for base and 4base, one has to reach the chroma
|
||
+data for 16 base:
|
||
+
|
||
+ - for 4base, after reading the 4base luma plane (and presumably
|
||
+ skipping the chroma planes) one sets cd_offset to the start of
|
||
+ the "current" sector
|
||
+
|
||
+ - for base, one has to skip the 4base data first:
|
||
+ - cd_offset is set to 384
|
||
+ - at (cd_offset+3 sectors)[510] is a 16 bit word high byte 1st
|
||
+ containing an offset to the beginning of the 16base stuff
|
||
+ though there is then a loop until >30 0xff's start a sector !
|
||
+
|
||
+ - being now positioned after the end of the 4base stuff,
|
||
+ - at (cd_offset+10 sectors)[2] is a 16 bit word high byte 1st
|
||
+ containing an offset to the chroma planes.
|
||
+ - at cd_offset+12 is the set of huffman tables
|
||
+
|
||
+ - for base, the 16base chroma planes are then halved
|
||
+*/
|
||
+
|
||
+ PCDSetParamOptions(bname);
|
||
+ if (theSize == -1)
|
||
+ {
|
||
+ PCDDialog(1); /* Open PCD Dialog box */
|
||
+ SetCursors(-1); /* Somebody has already set it to wait :( */
|
||
+ leaveitup=1;
|
||
+ goforit=0;
|
||
+ size = 1;
|
||
+ /* block until the popup window gets closed */
|
||
+ while (leaveitup) {
|
||
+ int i;
|
||
+ XEvent event;
|
||
+ XNextEvent(theDisp, &event);
|
||
+ HandleEvent(&event, &i);
|
||
+ }
|
||
+ /* At this point goforit and size will have been set */
|
||
+ if (!goforit) {
|
||
+ /* nothing allocated so nothing needs freeing */
|
||
+ return 0;
|
||
+ }
|
||
+ WaitCursor();
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ size = theSize;
|
||
+ goforit = 1;
|
||
+ }
|
||
+
|
||
+ if(lutCB.val)
|
||
+ rscale = gscale = bscale = 255.0/346.0;
|
||
+ else
|
||
+ rscale = gscale = bscale = 1.0;
|
||
+
|
||
+ switch (size) {
|
||
+ case 0:
|
||
+ pinfo->w = 192;
|
||
+ pinfo->h = 128;
|
||
+ offset=4*0x800;
|
||
+ mag=1;
|
||
+ huffplanes=0;
|
||
+ sprintf(pinfo->fullInfo, "PhotoCD, base/16 resolution");
|
||
+ break;
|
||
+
|
||
+ case 1:
|
||
+ pinfo->w = 384;
|
||
+ pinfo->h = 256;
|
||
+ offset=23*0x800;
|
||
+ mag=1;
|
||
+ huffplanes=0;
|
||
+ sprintf(pinfo->fullInfo, "PhotoCD, base/4 resolution");
|
||
+ break;
|
||
+
|
||
+ case 2:
|
||
+ default:
|
||
+ pinfo->w = 768;
|
||
+ pinfo->h = 512;
|
||
+ offset=96*0x800;
|
||
+ mag=1;
|
||
+ huffplanes=0;
|
||
+ sprintf(pinfo->fullInfo, "PhotoCD, base resolution");
|
||
+ break;
|
||
+
|
||
+ case 3:
|
||
+ pinfo->w = 1536;
|
||
+ pinfo->h = 1024;
|
||
+ offset=96*0x800;
|
||
+ mag=2;
|
||
+ huffplanes=1;
|
||
+ sprintf(pinfo->fullInfo, "PhotoCD, 4base resolution");
|
||
+ break;
|
||
+
|
||
+ case 4:
|
||
+ pinfo->w=3072;
|
||
+ pinfo->h=2048;
|
||
+ offset=96*0x800;
|
||
+ mag=4;
|
||
+ huffplanes=2;
|
||
+ sprintf(pinfo->fullInfo, "PhotoCD, 16base resolution");
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * rotate?
|
||
+ */
|
||
+ w = pinfo->w;
|
||
+ h = pinfo->h;
|
||
+ switch(rotate) {
|
||
+ case 0:
|
||
+ break;
|
||
+
|
||
+ case 1:
|
||
+ case 3:
|
||
+ pinfo->w = h;
|
||
+ pinfo->h = w;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ fprintf(stderr, "unknown image rotate %d; assuming none\n",
|
||
+ rotate);
|
||
+ rotate = 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * allocate 24-bit image
|
||
+ */
|
||
+ npixels = pinfo->w * pinfo->h;
|
||
+ bufsize = 3 * npixels;
|
||
+ if (pinfo->w <= 0 || pinfo->h <= 0 || npixels/pinfo->w != pinfo->h ||
|
||
+ bufsize/3 != npixels)
|
||
+ FatalError("image dimensions out of range");
|
||
+
|
||
+ pinfo->pic = (byte *)malloc((size_t) bufsize);
|
||
+ if(!pinfo->pic)
|
||
+ FatalError("couldn't malloc '24-bit RGB plane'");
|
||
+
|
||
+ pinfo->type = PIC24;
|
||
+ sprintf(pinfo->shrtInfo, "%dx%d PhotoCD.", pinfo->w, pinfo->h);
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ pinfo->frmType = -1;
|
||
+
|
||
+ if(fseek(fp, offset, SEEK_SET) == -1) {
|
||
+ free(pinfo->pic);
|
||
+ return pcdError(bname,"Can't find start of data.");
|
||
+ }
|
||
+
|
||
+ pic24 = pinfo->pic;
|
||
+
|
||
+ luma=(byte *)calloc(npixels,1);
|
||
+ if(!luma) {
|
||
+ free(pinfo->pic);
|
||
+ FatalError("couldn't malloc 'luma plane'");
|
||
+ }
|
||
+
|
||
+ chroma1=(byte *)calloc(npixels/4,1);
|
||
+ if(!chroma1) {
|
||
+ free(pinfo->pic);
|
||
+ free(luma);
|
||
+ FatalError("couldn't malloc 'chroma1 plane'");
|
||
+ }
|
||
+
|
||
+ chroma2=(byte *)calloc(npixels/4,1);
|
||
+ if(!chroma2) {
|
||
+ free(pinfo->pic);
|
||
+ free(luma);
|
||
+ free(chroma1);
|
||
+ FatalError("couldn't malloc 'chroma2 plane'");
|
||
+ }
|
||
+
|
||
+ /* Read 2 luma rows length w, then one of each chroma rows w/2 */
|
||
+ /* If a mag factor is active, the small image is read into the */
|
||
+ /* top right hand corner of the larger allocated image */
|
||
+
|
||
+ trace((stderr, "base image: start @ 0x%08lx (sector %ld.%ld)\n",
|
||
+ ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
|
||
+ for(row=0,lptr=luma,c1ptr=chroma1,c2ptr=chroma2; row <h/mag;
|
||
+ row+=2,lptr+=w*2,c1ptr+=w/2,c2ptr+=w/2) {
|
||
+ if(fread(lptr, 1, w/mag, fp) != w/mag) {
|
||
+ pcdError(bname, "Luma plane too short.");
|
||
+ break;
|
||
+ }
|
||
+ if(fread(lptr+w, 1, w/mag, fp) != w/mag) {
|
||
+ pcdError(bname, "Luma plane too short.");
|
||
+ break;
|
||
+ }
|
||
+ if(fread(c1ptr, 1, w/2/mag, fp) != w/2/mag) {
|
||
+ pcdError(bname, "Chroma1 plane too short.");
|
||
+ break;
|
||
+ }
|
||
+ if(fread(c2ptr, 1, w/2/mag, fp) != w/2/mag) {
|
||
+ pcdError(bname, "Chroma2 plane too short.");
|
||
+ break;
|
||
+ }
|
||
+ if(row%wcurfactor == 0)
|
||
+ WaitCursor();
|
||
+ }
|
||
+ trace((stderr, "base image: done @ 0x%08lx (sector %ld.%ld)\n",
|
||
+ ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
|
||
+
|
||
+ if(huffplanes) {
|
||
+ if(fseek(fp, 388*0x800, SEEK_SET) == -1)
|
||
+ return pcdError(bname,
|
||
+ "Can't find start of huffman tables.");
|
||
+
|
||
+ magnify(2, h/mag, w/mag, h, w, luma);
|
||
+ magnify(2, h/2/mag, w/2/mag, h/2, w/2, chroma1);
|
||
+ magnify(2, h/2/mag, w/2/mag, h/2, w/2, chroma2);
|
||
+
|
||
+ /*
|
||
+ * doesn't really touch the chroma planes which aren't
|
||
+ * present in 4base
|
||
+ */
|
||
+ gethuffdata(luma, chroma1, chroma2, w, h/mag*2);
|
||
+
|
||
+ /*
|
||
+ * if only doing 4base should probably fetch 16bases
|
||
+ * chroma planes here
|
||
+ */
|
||
+ if(huffplanes == 2) {
|
||
+ /*
|
||
+ * This depends on gethuffdata() having grabbed
|
||
+ * things in 0x800 sectors AND still being
|
||
+ * positioned in the "last" sector of the data
|
||
+ * (cf. Hadmut's code which is positioned at start
|
||
+ * of the next sector)
|
||
+ */
|
||
+ long offset = ftell(fp)/0x800+12;
|
||
+
|
||
+ if(fseek(fp, offset*0x800, SEEK_SET) == 0) {
|
||
+ magnify(2,h/2,w/2,h,w,luma);
|
||
+ magnify(2,h/4,w/4,h/2,w/2,chroma1);
|
||
+ magnify(2,h/4,w/4,h/2,w/2,chroma2);
|
||
+ gethuffdata(luma,chroma1,chroma2,w,h);
|
||
+ } else
|
||
+ fprintf(stderr, "can't seek to 2nd huffman tables\n");
|
||
+ }
|
||
+ }
|
||
+ fclose(fp);
|
||
+
|
||
+ /*
|
||
+ * YCC -> R'G'B' and image rotate
|
||
+ */
|
||
+ ptr=pic24;
|
||
+ lptr=luma; c1ptr=chroma1; c2ptr=chroma2;
|
||
+ for(row = 0; row < h; ++row) {
|
||
+ byte *rowc1ptr = c1ptr,
|
||
+ *rowc2ptr = c2ptr;
|
||
+ int k = 0;
|
||
+
|
||
+ switch(rotate) {
|
||
+ case 1:
|
||
+ ptr = &pic24[row*3 + (w - 1)*h*3];
|
||
+ k = -3*(h + 1);
|
||
+ break;
|
||
+
|
||
+ case 3:
|
||
+ ptr = &pic24[(h - 1 - row)*3];
|
||
+ k = 3*(h - 1);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ ptr = &pic24[row*w*3];
|
||
+ k = 0;
|
||
+ break;
|
||
+ }
|
||
+ for(col = 0; col < w; ++col) {
|
||
+ double L = 1.3584*(double) *lptr++,
|
||
+ C1 = 2.2179*(double) (*c1ptr - 156),
|
||
+ C2 = 1.8215*(double) (*c2ptr - 137);
|
||
+ int r = rscale*(L + C2),
|
||
+ g = gscale*(L - 0.194*C1 - 0.509*C2),
|
||
+ b = bscale*(L + C1);
|
||
+
|
||
+ if(lutCB.val) {
|
||
+ if(r < 0) r = 0; else if(r >= 255) r = 255;
|
||
+ if(g < 0) g = 0; else if(g >= 255) g = 255;
|
||
+ if(b < 0) b = 0; else if(b >= 255) b = 255;
|
||
+ } else {
|
||
+ if(r < 0) r = 0; else if(r >= 351) r = 350;
|
||
+ if(g < 0) g = 0; else if(g >= 351) g = 350;
|
||
+ if(b < 0) b = 0; else if(b >= 351) b = 350;
|
||
+ r = Y[r]; g = Y[g]; b = Y[b];
|
||
+ }
|
||
+ *ptr++ = r;
|
||
+ *ptr++ = g;
|
||
+ *ptr++ = b;
|
||
+ ptr += k;
|
||
+ if(col & 1) {
|
||
+ ++c1ptr;
|
||
+ ++c2ptr;
|
||
+ }
|
||
+ }
|
||
+ if((row & 1) == 0) {
|
||
+ c1ptr = rowc1ptr;
|
||
+ c2ptr = rowc2ptr;
|
||
+ }
|
||
+ if(row%wcurfactor == 0)
|
||
+ WaitCursor();
|
||
+ }
|
||
+ free(luma); free(chroma1); free(chroma2);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * derived from Hadmut Danisch's interpolate()
|
||
+ */
|
||
+static void
|
||
+magnify(int mag, /* power of 2 by which to magnify in place */
|
||
+ int h, int w, /* the "start" unmag'd dimensions of the array */
|
||
+ int mh, int mw, /* the real (maximum) dimensions of the array */
|
||
+ byte *p) /* pointer to the data */
|
||
+{
|
||
+ int x,y,yi;
|
||
+ byte *optr,*nptr,*uptr; /* MUST be unsigned, else averaging fails */
|
||
+
|
||
+ while (mag > 1) {
|
||
+
|
||
+ /* create every 2nd new row from 0 */
|
||
+ /* even pixels being equal to the old, odd ones averaged with successor */
|
||
+ /* special case being the last column which is just set equal to the */
|
||
+ /* second last) ... */
|
||
+
|
||
+ for(y=0;y<h;y++) {
|
||
+ yi=h-1-y;
|
||
+ optr=p+ yi*mw + (w-1); /* last pixel of an old row */
|
||
+ nptr=p+2*yi*mw + (2*w - 2); /* last pixel of a new row */
|
||
+
|
||
+ nptr[0]=nptr[1]=optr[0]; /* special cases */
|
||
+
|
||
+ for(x=1;x<w;x++) {
|
||
+ optr--; nptr-=2; /* next lower pixel(s) */
|
||
+ nptr[0]=optr[0]; /* even pixels duped */
|
||
+ nptr[1]=(((int)optr[0])+
|
||
+ ((int)optr[1])+1)>>1; /* odd averaged */
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Fill in odd rows, as average of prior & succeeding rows, with */
|
||
+ /* even pixels average of one column, odd pixels average of two */
|
||
+
|
||
+ for(y=0;y<h-1;y++) { /* all but the last old row */
|
||
+ optr=p + 2*y*mw; /* start of the new "even" rows */
|
||
+ nptr=optr+mw; /* start of the next empty row */
|
||
+ uptr=nptr+mw; /* start of the next again (even) */
|
||
+
|
||
+ for(x=0;x<w-1;x++) { /* for all cols except the last */
|
||
+ nptr[0]=(((int)optr[0])+
|
||
+ ((int)uptr[0])+1)>>1; /* even pixels */
|
||
+ nptr[1]=(((int)optr[0])+
|
||
+ ((int)optr[2])+
|
||
+ ((int)uptr[0])+
|
||
+ ((int)uptr[2])+2)>>2; /* odd pixels */
|
||
+ nptr+=2; optr+=2; uptr+=2;
|
||
+ }
|
||
+ *(nptr++)=(((int)*(optr++))+
|
||
+ ((int)*(uptr++))+1)>>1; /* 2nd last pixel */
|
||
+ *(nptr++)=(((int)*(optr++))+
|
||
+ ((int)*(uptr++))+1)>>1; /* last pixel */
|
||
+ }
|
||
+
|
||
+ xvbcopy((char *)(p + (2*h-2)*mw), /* 2nd last row */
|
||
+ (char *)(p + (2*h-1)*mw), /* the last row */
|
||
+ 2*w); /* length of a new row */
|
||
+
|
||
+ h*=2; w*=2;
|
||
+ mag>>=1; /* Obviously mag must be a power of 2 ! */
|
||
+ }
|
||
+}
|
||
+
|
||
+/*******************************************/
|
||
+static int
|
||
+pcdError(const char *fname, const char *st)
|
||
+{
|
||
+ SetISTR(ISTR_WARNING,"%s: %s", fname, st);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+/**** Stuff for PCDDialog box ****/
|
||
+
|
||
+#define TWIDE 380
|
||
+#define THIGH 160
|
||
+#define T_NBUTTS 2
|
||
+#define T_BOK 0
|
||
+#define T_BCANC 1
|
||
+#define BUTTH 24
|
||
+
|
||
+static void drawTD PARM((int, int, int, int));
|
||
+static void clickTD PARM((int, int));
|
||
+static void doCmd PARM((int));
|
||
+static void PCDSetParams PARM((void));
|
||
+
|
||
+/* local variables */
|
||
+static BUTT tbut[T_NBUTTS];
|
||
+static RBUTT *resnRB;
|
||
+
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+void CreatePCDW()
|
||
+{
|
||
+ int y;
|
||
+
|
||
+ pcdW = CreateWindow("xv pcd", "XVpcd", NULL,
|
||
+ TWIDE, THIGH, infofg, infobg, 0);
|
||
+ if (!pcdW) FatalError("can't create pcd window!");
|
||
+
|
||
+ XSelectInput(theDisp, pcdW, ExposureMask | ButtonPressMask | KeyPressMask);
|
||
+
|
||
+ BTCreate(&tbut[T_BOK], pcdW, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH,
|
||
+ "Ok", infofg, infobg, hicol, locol);
|
||
+
|
||
+ BTCreate(&tbut[T_BCANC], pcdW, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH,
|
||
+ "Cancel", infofg, infobg, hicol, locol);
|
||
+
|
||
+ y = 55;
|
||
+ resnRB = RBCreate(NULL, pcdW, 36, y, "192*128 Base/16",
|
||
+ infofg, infobg,hicol,locol);
|
||
+ RBCreate(resnRB, pcdW, 36, y+18, "384*256 Base/4",
|
||
+ infofg, infobg,hicol,locol);
|
||
+ RBCreate(resnRB, pcdW, 36, y+36, "768*512 Base",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ RBCreate(resnRB, pcdW, TWIDE/2, y, "1536*1024 4Base",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ RBCreate(resnRB, pcdW, TWIDE/2, y+18, "3072*2048 16Base",
|
||
+ infofg, infobg, hicol, locol);
|
||
+
|
||
+ CBCreate(&lutCB, pcdW, TWIDE/2, y+36, "Linear LUT",
|
||
+ infofg, infobg, hicol, locol);
|
||
+
|
||
+ RBSelect(resnRB, 2);
|
||
+
|
||
+ XMapSubwindows(theDisp, pcdW);
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+void PCDDialog(vis)
|
||
+int vis;
|
||
+{
|
||
+ if (vis) {
|
||
+ CenterMapWindow(pcdW, tbut[T_BOK].x + tbut[T_BOK].w/2,
|
||
+ tbut[T_BOK].y + tbut[T_BOK].h/2, TWIDE, THIGH);
|
||
+ }
|
||
+ else XUnmapWindow(theDisp, pcdW);
|
||
+ pcdUp = vis;
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+int PCDCheckEvent(xev)
|
||
+XEvent *xev;
|
||
+{
|
||
+ /* check event to see if it's for one of our subwindows. If it is,
|
||
+ deal accordingly, and return '1'. Otherwise, return '0' */
|
||
+
|
||
+ int rv;
|
||
+ rv = 1;
|
||
+
|
||
+ if (!pcdUp) return 0;
|
||
+
|
||
+ if (xev->type == Expose) {
|
||
+ int x,y,w,h;
|
||
+ XExposeEvent *e = (XExposeEvent *) xev;
|
||
+ x = e->x; y = e->y; w = e->width; h = e->height;
|
||
+
|
||
+ if (e->window == pcdW) drawTD(x, y, w, h);
|
||
+ else rv = 0;
|
||
+ }
|
||
+
|
||
+ else if (xev->type == ButtonPress) {
|
||
+ XButtonEvent *e = (XButtonEvent *) xev;
|
||
+ int x,y;
|
||
+ x = e->x; y = e->y;
|
||
+
|
||
+ if (e->button == Button1) {
|
||
+ if (e->window == pcdW) clickTD(x,y);
|
||
+ else rv = 0;
|
||
+ } /* button1 */
|
||
+ else rv = 0;
|
||
+ } /* button press */
|
||
+
|
||
+
|
||
+ else if (xev->type == KeyPress) {
|
||
+ XKeyEvent *e = (XKeyEvent *) xev;
|
||
+ char buf[128]; KeySym ks; XComposeStatus status;
|
||
+ int stlen;
|
||
+
|
||
+ stlen = XLookupString(e,buf,128,&ks,&status);
|
||
+ buf[stlen] = '\0';
|
||
+
|
||
+ RemapKeyCheck(ks, buf, &stlen);
|
||
+
|
||
+ if (e->window == pcdW) {
|
||
+ if (stlen) {
|
||
+ if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
|
||
+ FakeButtonPress(&tbut[T_BOK]);
|
||
+ }
|
||
+ else if (buf[0] == '\033') { /* ESC */
|
||
+ FakeButtonPress(&tbut[T_BCANC]);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else rv = 0;
|
||
+ }
|
||
+ else rv = 0;
|
||
+
|
||
+ if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
|
||
+ XBell(theDisp, 50);
|
||
+ rv = 1; /* eat it */
|
||
+ }
|
||
+
|
||
+ return rv;
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+void
|
||
+PCDSetParamOptions(const char *fname)
|
||
+{
|
||
+ int cur;
|
||
+ cur = RBWhich(resnRB);
|
||
+
|
||
+ RBSetActive(resnRB,0,1);
|
||
+ RBSetActive(resnRB,1,1);
|
||
+ RBSetActive(resnRB,2,1);
|
||
+ RBSetActive(resnRB,3,1);
|
||
+ RBSetActive(resnRB,4,1);
|
||
+ CBSetActive(&lutCB,1);
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+static void
|
||
+drawTD(int x, int y, int w, int h)
|
||
+{
|
||
+ const char *title = "Load PhotoCD file...";
|
||
+ int i;
|
||
+ XRectangle xr;
|
||
+
|
||
+ xr.x = x; xr.y = y; xr.width = w; xr.height = h;
|
||
+ XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
|
||
+
|
||
+ XSetForeground(theDisp, theGC, infofg);
|
||
+ XSetBackground(theDisp, theGC, infobg);
|
||
+
|
||
+ for (i=0; i<T_NBUTTS; i++) BTRedraw(&tbut[i]);
|
||
+
|
||
+ ULineString(pcdW, resnRB->x-16, resnRB->y-10-DESCENT, "Resolution");
|
||
+ RBRedraw(resnRB, -1);
|
||
+ CBRedraw(&lutCB);
|
||
+
|
||
+ XDrawString(theDisp, pcdW, theGC, 20, 19, title, strlen(title));
|
||
+
|
||
+ XSetClipMask(theDisp, theGC, None);
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+static void clickTD(x,y)
|
||
+int x,y;
|
||
+{
|
||
+ int i;
|
||
+ BUTT *bp;
|
||
+
|
||
+ /* check BUTTs */
|
||
+
|
||
+ /* check the RBUTTS first, since they don't DO anything */
|
||
+ if ( (i=RBClick(resnRB, x,y)) >= 0) {
|
||
+ (void) RBTrack(resnRB, i);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ if(CBClick(&lutCB, x, y)) {
|
||
+ (void) CBTrack(&lutCB);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ for (i=0; i<T_NBUTTS; i++) {
|
||
+ bp = &tbut[i];
|
||
+ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
|
||
+ }
|
||
+
|
||
+ if (i<T_NBUTTS) { /* found one */
|
||
+ if (BTTrack(bp)) doCmd(i);
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+static void doCmd(cmd)
|
||
+int cmd;
|
||
+{
|
||
+ leaveitup=0;
|
||
+ goforit=0;
|
||
+ switch (cmd) {
|
||
+ case T_BOK: PCDSetParams();
|
||
+ goforit=1;
|
||
+ case T_BCANC: PCDDialog(0);
|
||
+ break;
|
||
+
|
||
+ default: break;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static void PCDSetParams()
|
||
+{
|
||
+ switch (RBWhich(resnRB)) {
|
||
+ case 0: size = 0; break;
|
||
+ case 1: size = 1; break;
|
||
+ case 2: size = 2; break;
|
||
+ case 3: size = 3; break;
|
||
+ case 4: size = 4; break;
|
||
+ case 5: size = 0; break;
|
||
+ default: size = 0; break;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Read the Huffman tables which consist of an unsigned byte # of entries
|
||
+ * (less 1) followed by up to 256 entries, each of which is a series of 4
|
||
+ * unsigned bytes - length, highseq, lowseq, and key.
|
||
+ *
|
||
+ * Store the huffman table into tree type structure:
|
||
+ *
|
||
+ * int int[n of entries*2]
|
||
+ *
|
||
+ * Each entry consists of two words (the 1st for zero and the 2nd for one).
|
||
+ *
|
||
+ * If the word is negative, then subtract it from the current pointer to
|
||
+ * get the next entry (ie. it is the negative offset from the current
|
||
+ * position*2 in order to skip entries not words) with which to
|
||
+ * make a decision.
|
||
+ *
|
||
+ * If the word is not negative, then the low 8 bits contain the value (which
|
||
+ * is supposed to be a signed char) and the rest of the word is zero.
|
||
+ */
|
||
+static void
|
||
+dumphufftab(int n, const byte *h, int m, const int *t)
|
||
+{
|
||
+ int j;
|
||
+
|
||
+ for(j = 0; j < n || j < m; ++j) {
|
||
+ if(j < m)
|
||
+ fprintf(stderr, "%04x %04x ::", 0xffff & t[2*j + 0],
|
||
+ 0xffff & t[2*j + 1]);
|
||
+ else
|
||
+ fprintf(stderr, "%s %s ::", " ", " ");
|
||
+ if(j < n) {
|
||
+ int k;
|
||
+ unsigned l = (h[4*j + 1] << 8) | h[4*j + 2];
|
||
+
|
||
+ fprintf(stderr, " %02x %2d ", h[4*j + 3], h[4*j + 0]);
|
||
+ for(k = 0; k <= h[4*j + 0]; ++k, l *= 2)
|
||
+ fprintf(stderr, "%c", '0'+((l & 0x8000) != 0));
|
||
+ }
|
||
+ fprintf(stderr, "\n");
|
||
+ }
|
||
+}
|
||
+
|
||
+static int *
|
||
+gethufftable(void)
|
||
+{
|
||
+ int *hufftab, *h, i, j, N, num, bufsize, huffptr, hufftop;
|
||
+ byte *huf;
|
||
+
|
||
+ /*
|
||
+ * absorb the entirety of the table in one chunk (for better
|
||
+ * dumps in case of error)
|
||
+ */
|
||
+ trace((stderr, "hufftab 0x%08lx ", ftell(fp)));
|
||
+ num = 1 + fgetc(fp); /* 256 max */
|
||
+ huf = (byte *)alloca(4*num*sizeof(byte));
|
||
+ if((i = fread(huf, 1, 4*num, fp)) != 4*num) {
|
||
+ fprintf(stderr, "unexpected EOF: got %d bytes, wanted %d\n",
|
||
+ i, 4*num);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * guess an initial size and prepare the initial entry
|
||
+ */
|
||
+ trace((stderr, "length %u\n", num));
|
||
+ N = 2*num; /* 512 max */
|
||
+ bufsize = N * sizeof(int);
|
||
+/* this case can't happen, but added for symmetry with loop below
|
||
+ if (N/2 != num || bufsize/N != sizeof(int)) {
|
||
+ SetISTR(ISTR_WARNING, "Huffman table size out of range");
|
||
+ return NULL;
|
||
+ }
|
||
+ */
|
||
+ if((hufftab = (int *)malloc(bufsize)) == NULL)
|
||
+ FatalError("couldn't malloc initial Huffman table");
|
||
+ hufftab[0] = hufftab[1] = 0;
|
||
+
|
||
+ /*
|
||
+ * we check the table for reasonableness; there is a lack of detailed
|
||
+ * documentation on this format. in particular, for the base16,
|
||
+ * the position of the huffman tables is uncertain to within one
|
||
+ * "sector", and we have to detect his before trying to read
|
||
+ * bogusness.
|
||
+ */
|
||
+ hufftop = 0;
|
||
+ for(i = 0; i < num; ++i) {
|
||
+ unsigned length = huf[4*i + 0],
|
||
+ codeword = (huf[4*i + 1] << 8) | huf[4*i + 2];
|
||
+
|
||
+ /*
|
||
+ * some sanity checks
|
||
+ */
|
||
+ if(length >= 16) {
|
||
+ fprintf(stderr,
|
||
+ "gethufftable: improbable length @ %d/%d\n",
|
||
+ i, num);
|
||
+ dumphufftab(num, huf, hufftop/2, hufftab);
|
||
+ free(hufftab);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * walk the whole set of codes
|
||
+ */
|
||
+ huffptr = 0;
|
||
+ for(j = 0; j < 16; ++j, codeword *= 2) {
|
||
+ /*
|
||
+ * choose the child node
|
||
+ */
|
||
+ if(codeword & 0x8000)
|
||
+ ++huffptr;
|
||
+
|
||
+ /*
|
||
+ * store value at end-of-code
|
||
+ */
|
||
+ if(j == length) {
|
||
+ /*
|
||
+ * more sanity
|
||
+ */
|
||
+ if((codeword *= 2) & 0xffff) {
|
||
+ fprintf(stderr,
|
||
+ "gethufftable: "
|
||
+ ":probable invalid code @ %d\n",
|
||
+ i);
|
||
+ dumphufftab(num, huf,
|
||
+ hufftop/2, hufftab);
|
||
+ free(hufftab);
|
||
+ return NULL;
|
||
+ }
|
||
+ hufftab[huffptr] = 1 + (int) huf[4*i + 3];
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * otherwise, follow the tree to date
|
||
+ */
|
||
+ if(hufftab[huffptr] < 0) {
|
||
+ huffptr -= hufftab[huffptr];
|
||
+ continue;
|
||
+ } else if(hufftab[huffptr] > 0) {
|
||
+ fprintf(stderr, "duplicate code %d %d/%d\n",
|
||
+ huffptr, i, num);
|
||
+ dumphufftab(num, huf, hufftop/2, hufftab);
|
||
+ free(hufftab);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * and if necessary, make the tree bigger
|
||
+ */
|
||
+ if((hufftop += 2) >= N) {
|
||
+ int oldN = N;
|
||
+#if TRACE
|
||
+ dumphufftab(num, huf, hufftop/2, hufftab);
|
||
+#endif
|
||
+ N *= 2;
|
||
+ bufsize = N*sizeof(int);
|
||
+ if (N/2 != oldN || bufsize/N != sizeof(int)) {
|
||
+ SetISTR(ISTR_WARNING,
|
||
+ "new Huffman table is too large");
|
||
+ free(hufftab);
|
||
+ return NULL;
|
||
+ }
|
||
+ h = (int *)realloc(hufftab, bufsize);
|
||
+ if(h == NULL) {
|
||
+ fprintf(stderr,
|
||
+ "Table overflow %d/%d\n",
|
||
+ i, num);
|
||
+ dumphufftab(num, huf,
|
||
+ hufftop/2, hufftab);
|
||
+ free(hufftab);
|
||
+ FatalError(
|
||
+ "couldn't realloc Huffman table");
|
||
+ }
|
||
+ hufftab = h;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * then add new ptr
|
||
+ */
|
||
+ hufftab[huffptr] = huffptr - hufftop;
|
||
+ huffptr = hufftop;
|
||
+ hufftab[huffptr + 0] =
|
||
+ hufftab[huffptr + 1] = 0;
|
||
+ }
|
||
+ }
|
||
+ return hufftab;
|
||
+}
|
||
+
|
||
+/* WORDTYPE & char buffer must be unsigned else */
|
||
+/* fills with sign bit not 0 on right shifts */
|
||
+typedef unsigned int WORDTYPE;
|
||
+typedef int SWORDTYPE;
|
||
+#define WORDSIZE sizeof(WORDTYPE)
|
||
+#define NBYTESINBUF 0x800
|
||
+
|
||
+static byte buffer[NBYTESINBUF];
|
||
+static int bitsleft=0;
|
||
+static int bytesleft=0;
|
||
+static byte *bufptr;
|
||
+static WORDTYPE word;
|
||
+
|
||
+#if 0
|
||
+static void
|
||
+dumpbuffer(void)
|
||
+{
|
||
+ int i,left;
|
||
+ byte *ptr=buffer;
|
||
+
|
||
+ fprintf(stderr,"dumpbuffer: bytesleft=%d bitsleft= %d word=0x%08lx\n",
|
||
+ bytesleft,bitsleft,(unsigned long)word);
|
||
+ for (left=NBYTESINBUF; left>0; left-=16) {
|
||
+ fprintf(stderr,"%05d ",left);
|
||
+ for (i=0; i<8; i++) {
|
||
+ fprintf(stderr,"%02x",*ptr++);
|
||
+ fprintf(stderr,"%02x ",*ptr++);
|
||
+ }
|
||
+ fprintf(stderr,"\n");
|
||
+ }
|
||
+}
|
||
+#endif /* 0 */
|
||
+
|
||
+static void
|
||
+loadbuffer(void)
|
||
+{
|
||
+ if ((bytesleft=fread(buffer,1,NBYTESINBUF,fp)) == 0) {
|
||
+ fprintf(stderr,"Truncation error\n");
|
||
+ exit(1);
|
||
+ }
|
||
+ bufptr=buffer;
|
||
+ /* dumpbuffer(); */
|
||
+}
|
||
+
|
||
+static void
|
||
+loadbyte(void)
|
||
+{
|
||
+ if (bytesleft <= 0) loadbuffer();
|
||
+ --bytesleft;
|
||
+ word|=(WORDTYPE)(*bufptr++)<<(sizeof(WORDTYPE)*8-8-bitsleft);
|
||
+ bitsleft+=8;
|
||
+}
|
||
+
|
||
+static int
|
||
+getbit(void)
|
||
+{
|
||
+ int bit;
|
||
+
|
||
+ while (bitsleft <= 0) loadbyte();
|
||
+ --bitsleft;
|
||
+ bit=(SWORDTYPE)(word)<0; /* assumes word is signed */
|
||
+ /* bit=word>>(sizeof(WORDTYPE)*8-1); */
|
||
+ word<<=1;
|
||
+ return bit;
|
||
+}
|
||
+
|
||
+static WORDTYPE
|
||
+getnn(int nn)
|
||
+{
|
||
+ WORDTYPE value;
|
||
+
|
||
+ while (bitsleft <= nn) loadbyte();
|
||
+ bitsleft-=nn;
|
||
+ value=word>>(sizeof(WORDTYPE)*8-nn);
|
||
+ word<<=nn;
|
||
+ return value;
|
||
+}
|
||
+
|
||
+static WORDTYPE
|
||
+isnn(int nn)
|
||
+{
|
||
+ WORDTYPE value;
|
||
+
|
||
+ while (bitsleft <= nn) loadbyte();
|
||
+ value=word>>(sizeof(WORDTYPE)*8-nn);
|
||
+ return value;
|
||
+}
|
||
+
|
||
+static void
|
||
+skipnn(int nn)
|
||
+{
|
||
+ while (bitsleft <= nn) loadbyte();
|
||
+ bitsleft-=nn;
|
||
+ word<<=nn;
|
||
+}
|
||
+
|
||
+#define get1() (getbit())
|
||
+#define get2() (getnn(2))
|
||
+#define get8() (getnn(8))
|
||
+#define get13() (getnn(13))
|
||
+#define get16() (getnn(16))
|
||
+#define get24() (getnn(24))
|
||
+
|
||
+#define is24() (isnn(24))
|
||
+
|
||
+#define skip1() (skipnn(1))
|
||
+#define skip24() (skipnn(24))
|
||
+
|
||
+static int
|
||
+gethuffdata( byte *luma,
|
||
+ byte *chroma1,
|
||
+ byte *chroma2,
|
||
+ int realrowwidth,
|
||
+ int maxrownumber)
|
||
+{
|
||
+static byte clip[3*256];
|
||
+ int *hufftable[3], *huffstart = NULL, *huffptr = NULL;
|
||
+ int row, col, plane, i, result = 1;
|
||
+#if TRACE
|
||
+ int uflow = 0, oflow = 0;
|
||
+#endif
|
||
+ byte *pixelptr = NULL;
|
||
+
|
||
+ trace((stderr,"gethuffdata: start @ 0x%08lx (sector %ld.%ld)\n",
|
||
+ ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
|
||
+
|
||
+ /*
|
||
+ * correction clipping
|
||
+ */
|
||
+ if(clip[256+255] == 0) {
|
||
+ for(i = 0; i < 256; ++i)
|
||
+ clip[i + 0] = 0x00,
|
||
+ clip[i + 256] = (byte) i,
|
||
+ clip[i + 512] = 0xff;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * should really only look for luma plane for 4base, but the
|
||
+ * there are zeroes in the rest of the sector that give both
|
||
+ * chroma tables 0 length
|
||
+ */
|
||
+ for(i = 0; i < 3; ++i)
|
||
+ hufftable[i] = NULL;
|
||
+ for(i = 0; i < 3; ++i) {
|
||
+ if((hufftable[i] = gethufftable()) == NULL) {
|
||
+ result = 0;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if(result == 0)
|
||
+ goto oops;
|
||
+
|
||
+ /*
|
||
+ * skip remainder of current sector
|
||
+ */
|
||
+ i = (ftell(fp) | 0x7ff) + 1;
|
||
+ if(fseek(fp, i, SEEK_SET) < 0) {
|
||
+ fprintf(stderr, "gethuffdata: sector skip failed\n");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * skip remainder of "sector"
|
||
+ */
|
||
+ i = 0;
|
||
+ while (is24() != 0xfffffe) {
|
||
+ (void)get24();
|
||
+ if(++i == 1)
|
||
+ trace((stderr,"gethuffdata: skipping for sync ..."));
|
||
+ }
|
||
+ if(i != 0)
|
||
+ trace((stderr, " %d times\n", i));
|
||
+
|
||
+ while(result) {
|
||
+ if(is24() == 0xfffffe) {
|
||
+ skip24();
|
||
+ plane = get2();
|
||
+ row = get13(); col = 0;
|
||
+ skip1();
|
||
+ if(row >= maxrownumber) {
|
||
+ trace((stderr,
|
||
+ "gethuffdata: stopping at row %d\n",
|
||
+ row));
|
||
+ break;
|
||
+ }
|
||
+ switch (plane) {
|
||
+ case 0:
|
||
+ huffstart = hufftable[0];
|
||
+ pixelptr = luma + row*realrowwidth;
|
||
+ break;
|
||
+
|
||
+ case 2:
|
||
+ huffstart = hufftable[1];
|
||
+ pixelptr = chroma1 + row/2*realrowwidth/2;
|
||
+ break;
|
||
+
|
||
+ case 3:
|
||
+ huffstart = hufftable[2];
|
||
+ pixelptr = chroma2 + row/2*realrowwidth/2;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ fprintf(stderr, "gethuffdata: bad plane %d\n",
|
||
+ plane);
|
||
+ result = 0;
|
||
+ break;
|
||
+ }
|
||
+ WaitCursor();
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * locate correction in huffman tree
|
||
+ */
|
||
+ for(huffptr = huffstart;;) {
|
||
+ huffptr += get1();
|
||
+ if(*huffptr < 0) {
|
||
+ huffptr -= *huffptr;
|
||
+ } else if(*huffptr == 0) {
|
||
+ fprintf(stderr,
|
||
+ "gethuffdata: invalid code: "
|
||
+ "image quality reduced\n");
|
||
+ result = 0;
|
||
+ break;
|
||
+ } else
|
||
+ break;
|
||
+ }
|
||
+ if(!result)
|
||
+ break;
|
||
+
|
||
+ /*
|
||
+ * apply correction to the pixel
|
||
+ *
|
||
+ * eeeek!! the corrections can sometimes over or underflow!
|
||
+ * this strongly suggested that the 'magnify' method was in
|
||
+ * some way wrong. however, experiments showed that the
|
||
+ * over/under flows even occured for the pixels that are
|
||
+ * copied through magnify without change (ie, the even
|
||
+ * row/even column case). curiously, though, the odd
|
||
+ * column and odd row cases were about 3x more likely to have
|
||
+ * the over/underflow, and the odd row/odd column case was
|
||
+ * about 5x higher, so maybe the use of a bi-linear
|
||
+ * interpolation is not correct -- just *close*?
|
||
+ *
|
||
+ * the other clue in this area is that the overflows are
|
||
+ * by far most frequenct along edges of very bright
|
||
+ * areas -- rarely in the interior of such regions.
|
||
+ */
|
||
+ i = (int) *pixelptr + (signed char) (*huffptr - 1);
|
||
+#if TRACE
|
||
+ if(i > 255)
|
||
+ ++oflow;
|
||
+/* trace((stderr,
|
||
+ "gethuffdata: oflow %d %d %d\n", row, col, i));*/
|
||
+ else if(i < 0)
|
||
+ ++uflow;
|
||
+/* trace((stderr,
|
||
+ "gethuffdata: uflow %d %d %d\n", row, col, i));*/
|
||
+ ++col;
|
||
+#endif
|
||
+ *pixelptr++ = clip[i + 256];
|
||
+ }
|
||
+
|
||
+oops:
|
||
+ for(i = 0; i < 3; ++i)
|
||
+ free(hufftable[i]);
|
||
+ trace((stderr, "gethuffdata: uflow=%d oflow=%d\n", uflow, oflow));
|
||
+ trace((stderr, "gethuffdata: done @ 0x%08lx (sector %ld.%d)\n",
|
||
+ ftell(fp), ftell(fp)/0x800, 0x800 - bytesleft));
|
||
+ return result;
|
||
+}
|
||
+
|
||
+#endif /* HAVE_PCD */
|
||
diff -u -r --new-file xv-3.10a.orig/xvpi.c xv-3.10a/xvpi.c
|
||
--- xv-3.10a.orig/xvpi.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvpi.c 2005-04-18 00:57:04.000000000 -0500
|
||
@@ -0,0 +1,1060 @@
|
||
+/*
|
||
+ * xvpi.c - load routine for `Pi' format pictures.
|
||
+ *
|
||
+ * The `Pi' format is made by Yanagisawa.
|
||
+ * It is common among many Japanese personal computer users.
|
||
+ *
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+#include <setjmp.h>
|
||
+
|
||
+#ifdef HAVE_PI
|
||
+
|
||
+typedef unsigned short data16;
|
||
+typedef unsigned int data32;
|
||
+
|
||
+struct pi_info {
|
||
+ jmp_buf jmp;
|
||
+ FILE *fp;
|
||
+ struct {
|
||
+ int rest;
|
||
+ byte cur;
|
||
+ }bs;
|
||
+ long fsize;
|
||
+ byte mode;
|
||
+ int width, height;
|
||
+ float aspect;
|
||
+ int cbits;
|
||
+ int numcols;
|
||
+ byte *cmap;
|
||
+ struct ct_t{
|
||
+ struct elt_t *top;
|
||
+ struct elt_t{
|
||
+ struct elt_t *old, *recent;
|
||
+ byte val;
|
||
+ } *elt;
|
||
+ }*ct;
|
||
+ int defcmap;
|
||
+ int writing_grey;
|
||
+};
|
||
+
|
||
+static void pi_open_file PARM((struct pi_info*, char*));
|
||
+static void pi_read_header PARM((struct pi_info*, char**));
|
||
+static void pi_check_id PARM((struct pi_info*));
|
||
+static void pi_read_comment PARM((struct pi_info*, char**));
|
||
+static void pi_read_palette PARM((struct pi_info*));
|
||
+static void pi_expand PARM((struct pi_info*, byte**));
|
||
+static byte pi_read_color PARM((struct pi_info*, int));
|
||
+static int pi_read_position PARM((struct pi_info*));
|
||
+static data32 pi_read_length PARM((struct pi_info*));
|
||
+static int pi_copy_pixels PARM((struct pi_info*,
|
||
+ byte*, int, int, data32));
|
||
+
|
||
+static void pi_write_header PARM((struct pi_info*,
|
||
+ char*, byte*, byte*, byte*));
|
||
+static void pi_write_id PARM((struct pi_info*));
|
||
+static void pi_write_comment PARM((struct pi_info*, char*));
|
||
+static void pi_write_palette PARM((struct pi_info*, byte*, byte*, byte*));
|
||
+static void pi_compress PARM((struct pi_info*, byte*));
|
||
+static void pi_write_gabage PARM((struct pi_info*));
|
||
+static void pi_write_color PARM((struct pi_info*, int, int));
|
||
+static int pi_test_matching PARM((struct pi_info*,
|
||
+ byte*, int, int, data32*));
|
||
+static void pi_write_position PARM((struct pi_info*, int));
|
||
+static void pi_write_length PARM((struct pi_info*, data32));
|
||
+
|
||
+static void pi_table_create PARM((struct pi_info*));
|
||
+static byte pi_table_get_value PARM((struct pi_info*, int, int));
|
||
+static int pi_table_lookup_value PARM((struct pi_info*, int, int));
|
||
+static data32 pi_read_bits PARM((struct pi_info*, int));
|
||
+static void pi_write_bits PARM((struct pi_info*, data32, int));
|
||
+static void pi_init_pi_info PARM((struct pi_info*));
|
||
+static void pi_cleanup_pi_info PARM((struct pi_info*, int));
|
||
+static void pi_cleanup_pinfo PARM((PICINFO*));
|
||
+static void pi_memory_error PARM((char*, char*));
|
||
+static void pi_error PARM((struct pi_info*, int));
|
||
+static void pi_file_error PARM((struct pi_info*, int));
|
||
+static void pi_file_warning PARM((struct pi_info*, int));
|
||
+static void pi_show_pi_info PARM((struct pi_info*));
|
||
+static void *pi_malloc PARM((size_t, char*));
|
||
+static void *pi_realloc PARM((void*, size_t, char*));
|
||
+
|
||
+
|
||
+static char *pi_id = "Pi";
|
||
+static char *pi_msgs[] = {
|
||
+ NULL,
|
||
+#define PI_OPEN 1
|
||
+ "couldn't open.",
|
||
+#define PI_CORRUPT 2
|
||
+ "file corrupted.",
|
||
+#define PI_FORMAT 3
|
||
+ "not PI format.",
|
||
+#define PI_PLANES 4
|
||
+ "bad number of planes.",
|
||
+#define PI_WRITE 5
|
||
+ "write failed.",
|
||
+};
|
||
+
|
||
+
|
||
+/* The main routine of `Pi' loader. */
|
||
+int LoadPi(fname, pinfo)
|
||
+ char *fname;
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ struct pi_info pi;
|
||
+ int e;
|
||
+ int i;
|
||
+ if(DEBUG) fputs("LoadPi:\n", stderr);
|
||
+
|
||
+ pinfo->comment = NULL;
|
||
+ pi_init_pi_info(&pi);
|
||
+ if((e = setjmp(pi.jmp)) != 0){
|
||
+ /* When an error occurs, comes here. */
|
||
+ pi_cleanup_pi_info(&pi, 0);
|
||
+ pi_cleanup_pinfo(pinfo);
|
||
+ if(DEBUG) fputs("\n", stderr);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ pi_open_file(&pi, fname);
|
||
+ pi_read_header(&pi, &pinfo->comment);
|
||
+ pi_expand(&pi, &pinfo->pic);
|
||
+
|
||
+ pinfo->normw = pinfo->w = pi.width;
|
||
+ pinfo->normh = pinfo->h = pi.height;
|
||
+ pinfo->type = PIC8;
|
||
+ if(pi.numcols > 256) /* shouldn't happen. */
|
||
+ pi.numcols = 256;
|
||
+ for(i = 0; i < pi.numcols; i++){
|
||
+ pinfo->r[i] = pi.cmap[i * 3 ];
|
||
+ pinfo->g[i] = pi.cmap[i * 3 + 1];
|
||
+ pinfo->b[i] = pi.cmap[i * 3 + 2];
|
||
+ }
|
||
+ pinfo->frmType = F_PI;
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ sprintf(pinfo->fullInfo, "Pi, %d colors (%ld bytes)",
|
||
+ pi.numcols, pi.fsize);
|
||
+ sprintf(pinfo->shrtInfo, "%dx%d Pi.", pi.width, pi.height);
|
||
+ normaspect = pi.aspect;
|
||
+
|
||
+ pi_cleanup_pi_info(&pi, 0);
|
||
+ if(DEBUG) fputs("\n", stderr);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static void pi_open_file(pi, fname)
|
||
+ struct pi_info *pi;
|
||
+ char *fname;
|
||
+{
|
||
+ if((pi->fp = fopen(fname, "rb")) == NULL)
|
||
+ pi_file_error(pi, PI_OPEN);
|
||
+ fseek(pi->fp, (size_t) 0, SEEK_END);
|
||
+ pi->fsize = ftell(pi->fp);
|
||
+ fseek(pi->fp, (size_t) 0, SEEK_SET);
|
||
+}
|
||
+
|
||
+static void pi_read_header(pi, comm)
|
||
+ struct pi_info *pi;
|
||
+ char **comm;
|
||
+{
|
||
+ byte buf[10];
|
||
+ int mda;
|
||
+ int i;
|
||
+
|
||
+ pi_check_id(pi);
|
||
+ pi_read_comment(pi, comm);
|
||
+
|
||
+ if(fread(buf, (size_t) 10, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_CORRUPT);
|
||
+
|
||
+ pi->mode = buf[0];
|
||
+ pi->defcmap = pi->mode & 0x80;
|
||
+ if(buf[1] != 0 && buf[2] != 0)
|
||
+ pi->aspect = (float) buf[2] / (int) buf[1];
|
||
+ pi->cbits = buf[3];
|
||
+ pi->numcols = 1 << pi->cbits;
|
||
+
|
||
+ if(pi->cbits != 4 && pi->cbits != 8)
|
||
+ pi_error(pi, PI_PLANES);
|
||
+
|
||
+ mda = (int) buf[8] << 8 | (int) buf[9];
|
||
+ for(i = 0; i < mda; i++){
|
||
+ if(fgetc(pi->fp) == EOF)
|
||
+ pi_file_error(pi, PI_CORRUPT);
|
||
+ }
|
||
+
|
||
+ if(fread(buf, (size_t) 4, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_CORRUPT);
|
||
+ pi->width = (int) buf[0] << 8 | (int) buf[1];
|
||
+ pi->height = (int) buf[2] << 8 | (int) buf[3];
|
||
+
|
||
+ pi_read_palette(pi);
|
||
+
|
||
+ if(DEBUG) pi_show_pi_info(pi);
|
||
+}
|
||
+
|
||
+static void pi_check_id(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ char buf[2];
|
||
+
|
||
+ if(fread(buf, (size_t) 2, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_CORRUPT);
|
||
+ if(strncmp(buf, pi_id, (size_t) 2) != 0)
|
||
+ pi_error(pi, PI_FORMAT);
|
||
+}
|
||
+
|
||
+static void pi_read_comment(pi, comm)
|
||
+ struct pi_info *pi;
|
||
+ char **comm;
|
||
+{
|
||
+/*
|
||
+ * The comment format is like:
|
||
+ * comment string `^Z' dummy string `\0'
|
||
+ */
|
||
+ int max = -1, i = 0;
|
||
+ int c;
|
||
+
|
||
+ while(1){
|
||
+ if((c = fgetc(pi->fp)) == EOF)
|
||
+ pi_file_error(pi, PI_CORRUPT);
|
||
+ if(c == '\032') /* 0x1a, '^Z' */
|
||
+ break;
|
||
+ if(max < i){
|
||
+ max += 32;
|
||
+ *comm = pi_realloc(*comm, (size_t) max + 1, "pi_read_comment(1)");
|
||
+ }
|
||
+ (*comm)[i++] = c;
|
||
+ }
|
||
+ if(max < i){
|
||
+ max++;
|
||
+ *comm = pi_realloc(*comm, (size_t) max + 1, "pi_read_comment(2)");
|
||
+ }
|
||
+ (*comm)[i] = '\0';
|
||
+
|
||
+ while((c = fgetc(pi->fp)) != '\0'){ /* skip the dummy area */
|
||
+ if(c == EOF)
|
||
+ pi_file_error(pi, PI_CORRUPT);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pi_read_palette(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ pi->cmap = pi_malloc((size_t) pi->numcols * 3, "pi_read_palette");
|
||
+ if(pi->mode & 0x80){
|
||
+ if(pi->numcols == 16){
|
||
+ int i;
|
||
+ byte on;
|
||
+
|
||
+ on = 0x77;
|
||
+ for(i = 0; i < 8; i++){
|
||
+ pi->cmap[i * 3 ] = i & 2 ? on : 0;
|
||
+ pi->cmap[i * 3 + 1] = i & 4 ? on : 0;
|
||
+ pi->cmap[i * 3 + 2] = i & 1 ? on : 0;
|
||
+ }
|
||
+ on = 0xff;
|
||
+ for(; i < 16; i++){
|
||
+ pi->cmap[i * 3 ] = i & 2 ? on : 0;
|
||
+ pi->cmap[i * 3 + 1] = i & 4 ? on : 0;
|
||
+ pi->cmap[i * 3 + 2] = i & 1 ? on : 0;
|
||
+ }
|
||
+ }else{ /* pi->numcols == 256 */
|
||
+ int i;
|
||
+ byte r, g, b;
|
||
+ r = g = b = 0;
|
||
+ for(i = 0; i < 256; i++){
|
||
+ pi->cmap[i * 3 ] = r;
|
||
+ pi->cmap[i * 3 + 1] = g;
|
||
+ pi->cmap[i * 3 + 2] = b;
|
||
+ if((b += 0x40) == 0){
|
||
+ if((r += 0x20) == 0)
|
||
+ g += 0x20;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }else{
|
||
+ if(fread(pi->cmap, (size_t) pi->numcols * 3, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_CORRUPT);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* The main routine to expand `Pi' file. */
|
||
+static void pi_expand(pi, pic)
|
||
+ struct pi_info *pi;
|
||
+ byte **pic;
|
||
+{
|
||
+ byte prev_col = 0;
|
||
+ int prev_pos = -1;
|
||
+ int cnt = 0, max_cnt = pi->width * pi->height;
|
||
+
|
||
+ *pic = pi_malloc((size_t) max_cnt, "pi_expand"); // GRR POSSIBLE OVERFLOW / FIXME
|
||
+
|
||
+ pi_table_create(pi);
|
||
+
|
||
+ if(pi->width > 2){
|
||
+ (*pic)[0] = pi_read_color(pi, 0);
|
||
+ (*pic)[1] = pi_read_color(pi, (*pic)[0]);
|
||
+
|
||
+ while(cnt < max_cnt){
|
||
+ int pos = pi_read_position(pi);
|
||
+ if(pos != prev_pos){
|
||
+ data32 len = pi_read_length(pi);
|
||
+ cnt = pi_copy_pixels(pi, *pic, cnt, pos, len);
|
||
+ prev_col = (*pic)[cnt - 1];
|
||
+ prev_pos = pos;
|
||
+ }else{
|
||
+ do{
|
||
+ prev_col = pi_read_color(pi, (int) prev_col);
|
||
+ (*pic)[cnt++] = prev_col;
|
||
+ prev_col = pi_read_color(pi, (int) prev_col);
|
||
+ (*pic)[cnt++] = prev_col;
|
||
+ }while(pi_read_bits(pi, 1) == 1);
|
||
+
|
||
+ prev_pos = -1;
|
||
+ }
|
||
+ }
|
||
+ }else{
|
||
+ while(cnt < max_cnt){
|
||
+ prev_col = pi_read_color(pi, (int) prev_col);
|
||
+ (*pic)[cnt++] = prev_col;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static byte pi_read_color(pi, prev)
|
||
+ struct pi_info *pi;
|
||
+ int prev;
|
||
+{
|
||
+ byte n;
|
||
+ if(pi->cbits == 4){
|
||
+ if(pi_read_bits(pi, 1) == 1)
|
||
+ n = pi_read_bits(pi, 1); /* 1x */
|
||
+ else{
|
||
+ if(pi_read_bits(pi, 1) == 0)
|
||
+ n = pi_read_bits(pi, 1) + 2; /* 00x */
|
||
+ else{
|
||
+ if(pi_read_bits(pi, 1) == 0)
|
||
+ n = pi_read_bits(pi, 2) + 4; /* 010xx */
|
||
+ else
|
||
+ n = pi_read_bits(pi, 3) + 8; /* 011xxx */
|
||
+ }
|
||
+ }
|
||
+ }else{ /* cbits == 8 */
|
||
+ if(pi_read_bits(pi, 1) == 1)
|
||
+ n = pi_read_bits(pi, 1);
|
||
+ else{
|
||
+ int bits = 0;
|
||
+ byte base = 2;
|
||
+ while(bits < 6){
|
||
+ if(pi_read_bits(pi, 1) == 0)
|
||
+ break;
|
||
+ bits++;
|
||
+ base <<= 1;
|
||
+ }
|
||
+ n = pi_read_bits(pi, bits + 1) + base;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return pi_table_get_value(pi, prev, (int) n);
|
||
+}
|
||
+
|
||
+static int pi_read_position(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ byte r;
|
||
+ if((r = pi_read_bits(pi, 2)) != 3)
|
||
+ return (int) r;
|
||
+ else
|
||
+ return (int) pi_read_bits(pi, 1) + 3;
|
||
+}
|
||
+
|
||
+static data32 pi_read_length(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ data32 r = 1;
|
||
+ int bits = 0;
|
||
+ while(pi_read_bits(pi, 1) == 1){
|
||
+ r <<= 1;
|
||
+ bits++;
|
||
+ }
|
||
+ if(bits > 0)
|
||
+ return r + pi_read_bits(pi, bits);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static int pi_copy_pixels(pi, pic, cnt, pos, len)
|
||
+ struct pi_info *pi;
|
||
+ byte *pic;
|
||
+ int cnt, pos;
|
||
+ data32 len;
|
||
+{
|
||
+ int s = 0, d = cnt;
|
||
+ int max = pi->width * pi->height;
|
||
+ switch(pos){
|
||
+ case 0:
|
||
+ if(cnt < 2){
|
||
+ if(pic[0] == pic[1])
|
||
+ s = cnt - 2;
|
||
+ else
|
||
+ s = cnt - 4;
|
||
+ }else{
|
||
+ if(pic[cnt - 2] == pic[cnt - 1])
|
||
+ s = cnt - 2;
|
||
+ else
|
||
+ s = cnt - 4;
|
||
+ }
|
||
+ break;
|
||
+ case 1:
|
||
+ s = cnt - pi->width;
|
||
+ break;
|
||
+ case 2:
|
||
+ s = cnt - pi->width * 2;
|
||
+ break;
|
||
+ case 3:
|
||
+ s = cnt - pi->width + 1;
|
||
+ break;
|
||
+ case 4:
|
||
+ s = cnt - pi->width - 1;
|
||
+ }
|
||
+
|
||
+ len *= 2;
|
||
+ while(s < 0 && len != 0 && d < max){
|
||
+ pic[d++] = pic[-(s++) % 2];
|
||
+ len--;
|
||
+ }
|
||
+ while(len != 0 && d < max){
|
||
+ pic[d++] = pic[s++];
|
||
+ len--;
|
||
+ }
|
||
+ return d;
|
||
+}
|
||
+
|
||
+/* The main routine of `Pi' saver. */
|
||
+int WritePi(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
|
||
+ comment)
|
||
+ FILE *fp;
|
||
+ byte *pic;
|
||
+ int ptype, w, h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int numcols, colorstyle;
|
||
+ char *comment;
|
||
+{
|
||
+ byte rtemp[256], gtemp[256], btemp[256];
|
||
+ struct pi_info pi;
|
||
+ int e;
|
||
+
|
||
+ if(DEBUG) fputs("WritePi\n", stderr);
|
||
+ pi_init_pi_info(&pi);
|
||
+ pi.fp = fp;
|
||
+ pi.width = w;
|
||
+ pi.height = h;
|
||
+ pi.writing_grey = (colorstyle == F_GREYSCALE);
|
||
+ if(ptype == PIC24){
|
||
+ if(!(pic = Conv24to8(pic, w, h, 256, rtemp, gtemp, btemp)))
|
||
+ pi_memory_error("Conv24to8", "WritePi");
|
||
+ rmap = rtemp;
|
||
+ gmap = gtemp;
|
||
+ bmap = btemp;
|
||
+ numcols = 256;
|
||
+ }
|
||
+
|
||
+ if((e = setjmp(pi.jmp)) != 0){
|
||
+ /* When an error occurs, comes here. */
|
||
+ pi_cleanup_pi_info(&pi, 1);
|
||
+ if(DEBUG) fputs("\n", stderr);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ pi.numcols = numcols;
|
||
+ pi_write_header(&pi, comment, rmap, gmap, bmap);
|
||
+ pi_compress(&pi, pic);
|
||
+ pi_write_gabage(&pi);
|
||
+
|
||
+ pi_cleanup_pi_info(&pi, 1);
|
||
+ if(DEBUG) fputs("\n", stderr);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void pi_write_header(pi, comm, r, g, b)
|
||
+ struct pi_info *pi;
|
||
+ char *comm;
|
||
+ byte *r, *g, *b;
|
||
+{
|
||
+ byte buf[14];
|
||
+
|
||
+ if(DEBUG) pi_show_pi_info(pi);
|
||
+
|
||
+ pi_write_id(pi);
|
||
+ pi_write_comment(pi, comm);
|
||
+
|
||
+ buf[0] = buf[1] = buf[2] = 0;
|
||
+ buf[3] = pi->cbits = pi->numcols > 16 ? 8 : 4;
|
||
+ buf[4] = 'X';
|
||
+ buf[5] = 'V';
|
||
+ buf[6] = ' ';
|
||
+ buf[7] = ' ';
|
||
+ buf[8] = buf[9] = 0;
|
||
+ buf[10] = pi->width >> 8;
|
||
+ buf[11] = pi->width;
|
||
+ buf[12] = pi->height >> 8;
|
||
+ buf[13] = pi->height;
|
||
+ if(fwrite(buf, (size_t) 14, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_WRITE);
|
||
+
|
||
+ pi_write_palette(pi, r, g, b);
|
||
+}
|
||
+
|
||
+static void pi_write_id(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ if(fwrite(pi_id, (size_t) 2, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_WRITE);
|
||
+}
|
||
+
|
||
+static void pi_write_comment(pi, comm)
|
||
+ struct pi_info *pi;
|
||
+ char *comm;
|
||
+{
|
||
+ if(comm){
|
||
+ int i;
|
||
+ for(i = 0; comm[i]; i++){
|
||
+ if(comm[i] == '\032') /* 0x1a, '^Z' */
|
||
+ comm[i] = ' ';
|
||
+ }
|
||
+ if(i > 0){
|
||
+ if(fwrite(comm, (size_t) i, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_WRITE);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if(fwrite("\032\0", (size_t) 2, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_WRITE);
|
||
+}
|
||
+
|
||
+static void pi_write_palette(pi, r, g, b)
|
||
+ struct pi_info *pi;
|
||
+ byte *r, *g, *b;
|
||
+{
|
||
+ int i;
|
||
+ int pinum = 1 << pi->cbits;
|
||
+ char buf[3];
|
||
+
|
||
+ for(i = 0; i < pi->numcols; i++){
|
||
+ buf[0] = *r++;
|
||
+ buf[1] = *g++;
|
||
+ buf[2] = *b++;
|
||
+ if(pi->writing_grey)
|
||
+ buf[0] = buf[1] = buf[2] = MONO(buf[0], buf[1], buf[2]);
|
||
+ if(fwrite(buf, (size_t) 3, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_WRITE);
|
||
+ }
|
||
+ for( ; i < pinum; i++){
|
||
+ if(fwrite(buf, (size_t) 3, (size_t) 1, pi->fp) != 1)
|
||
+ pi_file_error(pi, PI_WRITE);
|
||
+ }
|
||
+ pi->numcols = pinum;
|
||
+}
|
||
+
|
||
+/* The main routine to compress `Pi' format. */
|
||
+static void pi_compress(pi, pic)
|
||
+ struct pi_info *pi;
|
||
+ byte *pic;
|
||
+{
|
||
+ byte prev_col = 0;
|
||
+ int prev_pos = -1;
|
||
+ int cnt = 0, max_cnt = pi->width * pi->height;
|
||
+ pi_table_create(pi);
|
||
+
|
||
+ if(pi->width > 2){
|
||
+ int pos;
|
||
+ data32 len;
|
||
+
|
||
+ pi_write_color(pi, 0, pic[0]);
|
||
+ pi_write_color(pi, pic[0], pic[1]);
|
||
+ pos = pi_test_matching(pi, pic, prev_pos, cnt, &len);
|
||
+ while(cnt < max_cnt){
|
||
+ if(pos >= 0){
|
||
+ pi_write_position(pi, pos);
|
||
+ pi_write_length(pi, len);
|
||
+ if((cnt += len * 2) >= max_cnt)
|
||
+ break;
|
||
+ prev_col = pic[cnt - 1];
|
||
+ prev_pos = pos;
|
||
+ pos = pi_test_matching(pi, pic, prev_pos, cnt, &len);
|
||
+ }else{
|
||
+ pi_write_position(pi, prev_pos);
|
||
+ prev_pos = -1;
|
||
+ while(pos < 0){
|
||
+ pi_write_color(pi, (int) prev_col, pic[cnt]);
|
||
+ prev_col = pic[cnt];
|
||
+ if(++cnt >= max_cnt)
|
||
+ break;
|
||
+ pi_write_color(pi, (int) prev_col, pic[cnt]);
|
||
+ prev_col = pic[cnt];
|
||
+ if(++cnt >= max_cnt)
|
||
+ break;
|
||
+ pos = pi_test_matching(pi, pic, -1, cnt, &len);
|
||
+ if(pos < 0)
|
||
+ pi_write_bits(pi, 1, 1);
|
||
+ else
|
||
+ pi_write_bits(pi, 0, 1);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }else{
|
||
+ while(cnt < max_cnt){
|
||
+ pi_write_color(pi, (int) prev_col, pic[cnt]);
|
||
+ prev_col = pic[cnt++];
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pi_write_gabage(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ pi_write_bits(pi, 0, 32);
|
||
+}
|
||
+
|
||
+static void pi_write_color(pi, prev, col)
|
||
+ struct pi_info *pi;
|
||
+ int prev, col;
|
||
+{
|
||
+ int n = pi_table_lookup_value(pi, prev, col);
|
||
+
|
||
+ if(pi->cbits == 4){
|
||
+ if(n < 2)
|
||
+ pi_write_bits(pi, (data32) n | 2, 2);
|
||
+ else if(n < 4)
|
||
+ pi_write_bits(pi, (data32) n - 2, 3);
|
||
+ else if(n < 8)
|
||
+ pi_write_bits(pi, (data32) (n - 4) | 8, 5);
|
||
+ else
|
||
+ pi_write_bits(pi, (data32) (n - 8) | 24, 6);
|
||
+ }else{ /* cbits == 8 */
|
||
+ if(n < 2){
|
||
+ pi_write_bits(pi, (data32) n | 2, 2);
|
||
+ }else{
|
||
+ int bits = 0;
|
||
+ byte base = 2;
|
||
+ while(bits < 6){
|
||
+ if(n < (int) base * 2)
|
||
+ break;
|
||
+ bits++;
|
||
+ base <<= 1;
|
||
+ }
|
||
+ pi_write_bits(pi, 0, 1);
|
||
+ if(bits > 0)
|
||
+ pi_write_bits(pi, 0xffffffff, bits);
|
||
+ if(bits < 6)
|
||
+ pi_write_bits(pi, 0, 1);
|
||
+ pi_write_bits(pi, (data32) n - base, bits + 1);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static int pi_test_matching(pi, pic, prev, cnt, len)
|
||
+ struct pi_info *pi;
|
||
+ byte *pic;
|
||
+ int prev, cnt;
|
||
+ data32 *len;
|
||
+{
|
||
+ data32 lens[5];
|
||
+ int pos, p;
|
||
+ int s, d = 0;
|
||
+ int max = pi->width * pi->height;
|
||
+
|
||
+ for(pos = 0; pos < 5; pos++){
|
||
+ switch(pos){
|
||
+ case 0:
|
||
+ if(cnt < 2){
|
||
+ if(pic[0] == pic[1])
|
||
+ d = cnt - 2;
|
||
+ else
|
||
+ d = cnt - 4;
|
||
+ }else{
|
||
+ if(pic[cnt - 2] == pic[cnt - 1])
|
||
+ d = cnt - 2;
|
||
+ else
|
||
+ d = cnt - 4;
|
||
+ }
|
||
+ break;
|
||
+ case 1:
|
||
+ d = cnt - pi->width;
|
||
+ break;
|
||
+ case 2:
|
||
+ d = cnt - pi->width * 2;
|
||
+ break;
|
||
+ case 3:
|
||
+ d = cnt - pi->width + 1;
|
||
+ break;
|
||
+ case 4:
|
||
+ d = cnt - pi->width - 1;
|
||
+ }
|
||
+ s = cnt;
|
||
+ lens[pos] = 0;
|
||
+
|
||
+ if(prev == 0 && pos == 0)
|
||
+ continue;
|
||
+
|
||
+ while(d < max){
|
||
+ if(pic[(d < 0) ? (-d) % 2 : d] != pic[s])
|
||
+ break;
|
||
+ lens[pos]++;
|
||
+ d++;
|
||
+ s++;
|
||
+ }
|
||
+
|
||
+ }
|
||
+
|
||
+ for(pos = 0, p = 1; p < 5; p++){
|
||
+ if(lens[p] >= lens[pos])
|
||
+ pos = p;
|
||
+ }
|
||
+
|
||
+ if(lens[pos] / 2 == 0)
|
||
+ return -1;
|
||
+ *len = lens[pos] / 2;
|
||
+ return pos;
|
||
+}
|
||
+
|
||
+static void pi_write_position(pi, pos)
|
||
+ struct pi_info *pi;
|
||
+ int pos;
|
||
+{
|
||
+ switch(pos){
|
||
+ case 0:
|
||
+ pi_write_bits(pi, 0, 2);
|
||
+ break;
|
||
+ case 1:
|
||
+ pi_write_bits(pi, 1, 2);
|
||
+ break;
|
||
+ case 2:
|
||
+ pi_write_bits(pi, 2, 2);
|
||
+ break;
|
||
+ case 3:
|
||
+ pi_write_bits(pi, 6, 3);
|
||
+ break;
|
||
+ case 4:
|
||
+ pi_write_bits(pi, 7, 3);
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pi_write_length(pi, len)
|
||
+ struct pi_info *pi;
|
||
+ data32 len;
|
||
+{
|
||
+ int bits = 0;
|
||
+ data32 base = 1;
|
||
+
|
||
+ while(len >= base * 2){
|
||
+ bits++;
|
||
+ base <<= 1;
|
||
+ }
|
||
+ if(bits > 0){
|
||
+ pi_write_bits(pi, 0xffffffff, bits);
|
||
+ pi_write_bits(pi, 0, 1);
|
||
+ pi_write_bits(pi, len - base, bits);
|
||
+ }else
|
||
+ pi_write_bits(pi, 0, 1);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These pi_table_* functions manipulate the color table.
|
||
+ * pi_table_create:
|
||
+ * allocates and initializes a color table.
|
||
+ * pi_table_get_value:
|
||
+ * get the specified value, and move it to the top of the list.
|
||
+ * pi_table_lookup_value:
|
||
+ * look up the specified value, and move it to the top of the list.
|
||
+ */
|
||
+static void pi_table_create(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ struct ct_t *t;
|
||
+ int i;
|
||
+ byte mask = pi->numcols - 1;
|
||
+ pi->ct = pi_malloc(sizeof *pi->ct * pi->numcols, "pi_table_create(1)");
|
||
+ for(i = 0, t = pi->ct; i < pi->numcols; i++, t++){
|
||
+ int j;
|
||
+ byte v = i;
|
||
+ t->elt = pi_malloc(sizeof *t->elt * pi->numcols, "pi_table_create(2)");
|
||
+ t->top = &t->elt[pi->numcols - 1];
|
||
+ for(j = 0; j < pi->numcols; j++){
|
||
+ v = (v + 1) & mask;
|
||
+ if(j > 0)
|
||
+ t->elt[j].old = &t->elt[j - 1];
|
||
+ else
|
||
+ t->elt[0].old = t->top;
|
||
+ if(j < pi->numcols - 1)
|
||
+ t->elt[j].recent = &t->elt[j + 1];
|
||
+ else
|
||
+ t->elt[j].recent = &t->elt[0];
|
||
+ t->elt[j].val = v;
|
||
+ }
|
||
+ t->elt[0].old = t->top;
|
||
+ t->top->recent = &t->elt[0];
|
||
+ }
|
||
+}
|
||
+
|
||
+static byte pi_table_get_value(pi, left, num)
|
||
+ struct pi_info *pi;
|
||
+ int left, num;
|
||
+{
|
||
+ struct ct_t *t = &pi->ct[left];
|
||
+ struct elt_t *e = t->top;
|
||
+ if(left >= pi->numcols || num >= pi->numcols)
|
||
+ abort();
|
||
+ if(num != 0){
|
||
+ do {
|
||
+ e = e->old;
|
||
+ }while(--num != 0);
|
||
+
|
||
+ e->old->recent = e->recent;
|
||
+ e->recent->old = e->old;
|
||
+
|
||
+ e->recent = t->top->recent;
|
||
+ e->recent->old = e;
|
||
+ e->old = t->top;
|
||
+ t->top->recent = e;
|
||
+
|
||
+ t->top = e;
|
||
+ }
|
||
+ return e->val;
|
||
+}
|
||
+
|
||
+static int pi_table_lookup_value(pi, left, v)
|
||
+ struct pi_info *pi;
|
||
+ int left, v;
|
||
+{
|
||
+ struct ct_t *t = &pi->ct[left];
|
||
+ struct elt_t *e = t->top;
|
||
+ int num = 0;
|
||
+
|
||
+ if(left >= pi->numcols || v >= pi->numcols)
|
||
+ abort();
|
||
+
|
||
+ while(e->val != v){
|
||
+ e = e->old;
|
||
+ num++;
|
||
+ }
|
||
+
|
||
+ if(num != 0){
|
||
+ e->old->recent = e->recent;
|
||
+ e->recent->old = e->old;
|
||
+
|
||
+ e->recent = t->top->recent;
|
||
+ e->recent->old = e;
|
||
+ e->old = t->top;
|
||
+ t->top->recent = e;
|
||
+
|
||
+ t->top = e;
|
||
+ }
|
||
+
|
||
+ return num;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These 2 functions read or write to a bit stream.
|
||
+ * pi_read_bits:
|
||
+ * reads a specified-bit data from the bit stream.
|
||
+ * pi_write_bits:
|
||
+ * writes a specified-bit data to the bit stream.
|
||
+ */
|
||
+static data32 pi_read_bits(pi, numbits)
|
||
+ struct pi_info *pi;
|
||
+ int numbits;
|
||
+{
|
||
+ data32 r = 0;
|
||
+
|
||
+ while(numbits > 0){
|
||
+ while(pi->bs.rest > 0 && numbits > 0){
|
||
+ r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0);
|
||
+ pi->bs.cur <<= 1;
|
||
+ pi->bs.rest--;
|
||
+ numbits--;
|
||
+ }
|
||
+ if(numbits > 0){
|
||
+ int c;
|
||
+ if((c = fgetc(pi->fp)) == EOF)
|
||
+ pi_file_warning(pi, PI_CORRUPT);
|
||
+ pi->bs.cur = c;
|
||
+ pi->bs.rest = 8;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return r;
|
||
+}
|
||
+
|
||
+static void pi_write_bits(pi, dat, bits)
|
||
+ struct pi_info *pi;
|
||
+ data32 dat;
|
||
+ int bits;
|
||
+{
|
||
+ data32 dat_mask = 1 << (bits - 1);
|
||
+ while(bits > 0){
|
||
+ while(pi->bs.rest < 8 && bits > 0){
|
||
+ pi->bs.cur <<= 1;
|
||
+ if(dat & dat_mask)
|
||
+ pi->bs.cur |= 1;
|
||
+ pi->bs.rest++;
|
||
+ bits--;
|
||
+ dat_mask >>= 1;
|
||
+ }
|
||
+ if(pi->bs.rest >= 8){
|
||
+ if(fputc((int)pi->bs.cur, pi->fp) == EOF)
|
||
+ pi_file_error(pi, PI_WRITE);
|
||
+ pi->bs.cur = 0;
|
||
+ pi->bs.rest = 0;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * The routines to initialize or clean up.
|
||
+ * pi_inif_pi_info:
|
||
+ * initializes a pi_info structure.
|
||
+ * pi_cleanup_pi_info:
|
||
+ * cleanup pi_info structure. It frees allocated memories.
|
||
+ * pi_cleanup_pinfo:
|
||
+ * cleanup PICINFO structure when an error occurs.
|
||
+ */
|
||
+static void pi_init_pi_info(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ pi->fp = NULL;
|
||
+ pi->bs.rest = 0;
|
||
+ pi->bs.cur = 0;
|
||
+ pi->fsize = 0;
|
||
+ pi->mode = 0;
|
||
+ pi->width = pi->mode = 0;
|
||
+ pi->aspect = 1.0;
|
||
+ pi->cbits = 0;
|
||
+ pi->numcols = 0;
|
||
+ pi->cmap = NULL;
|
||
+ pi->ct = NULL;
|
||
+ pi->defcmap = 0;
|
||
+ pi->writing_grey = 0;
|
||
+}
|
||
+
|
||
+static void pi_cleanup_pi_info(pi, writing)
|
||
+ struct pi_info *pi;
|
||
+ int writing;
|
||
+{
|
||
+ if(pi->fp && !writing){
|
||
+ fclose(pi->fp);
|
||
+ pi->fp = NULL;
|
||
+ }
|
||
+ if(pi->cmap){
|
||
+ free(pi->cmap);
|
||
+ pi->cmap = NULL;
|
||
+ }
|
||
+ if(pi->ct){
|
||
+ int i;
|
||
+ for(i = 0; i < pi->numcols; i++)
|
||
+ free(pi->ct[i].elt);
|
||
+ free(pi->ct);
|
||
+ pi->ct = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pi_cleanup_pinfo(pinfo)
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ if(pinfo->pic){
|
||
+ free(pinfo->pic);
|
||
+ pinfo->pic = NULL;
|
||
+ }
|
||
+ if(pinfo->comment){
|
||
+ free(pinfo->comment);
|
||
+ pinfo->comment = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Error handling routins.
|
||
+ * pi_memory_error:
|
||
+ * shows a error message, and terminates.
|
||
+ * pi_error:
|
||
+ * shows a non-file error message.
|
||
+ * pi_file_error:
|
||
+ * shows a file error message.
|
||
+ */
|
||
+static void pi_memory_error(scm, fn)
|
||
+ char *scm, *fn;
|
||
+{
|
||
+ char buf[128];
|
||
+ sprintf(buf, "%s: couldn't allocate memory. (%s)", scm ,fn);
|
||
+ FatalError(buf);
|
||
+}
|
||
+
|
||
+static void pi_error(pi, mn)
|
||
+ struct pi_info *pi;
|
||
+ int mn;
|
||
+{
|
||
+ SetISTR(ISTR_WARNING, "%s", pi_msgs[mn]);
|
||
+ longjmp(pi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void pi_file_error(pi, mn)
|
||
+ struct pi_info *pi;
|
||
+ int mn;
|
||
+{
|
||
+ if(feof(pi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", pi_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", pi_msgs[mn], ERRSTR(errno));
|
||
+ longjmp(pi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void pi_file_warning(pi, mn)
|
||
+ struct pi_info *pi;
|
||
+ int mn;
|
||
+{
|
||
+ if(feof(pi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", pi_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", pi_msgs[mn], ERRSTR(errno));
|
||
+}
|
||
+
|
||
+static void pi_show_pi_info(pi)
|
||
+ struct pi_info *pi;
|
||
+{
|
||
+ fprintf(stderr, " file size: %ld.\n", pi->fsize);
|
||
+ fprintf(stderr, " mode: 0x%02x.\n", pi->mode);
|
||
+ fprintf(stderr, " image size: %dx%d.\n", pi->width, pi->height);
|
||
+ fprintf(stderr, " aspect: %f.\n", pi->aspect);
|
||
+ fprintf(stderr, " number of color bits: %d.\n", pi->cbits);
|
||
+ fprintf(stderr, " number of colors: %d.\n", pi->numcols);
|
||
+ fprintf(stderr, " using default colormap: %s.\n",
|
||
+ pi->defcmap ? "true" : "false");
|
||
+ fprintf(stderr, " writing greyscale image: %s.\n",
|
||
+ pi->writing_grey ? "true" : "false");
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Memory related routines. If failed, they calls pi_memory_error.
|
||
+ */
|
||
+static void *pi_malloc(n, fn)
|
||
+ size_t n;
|
||
+ char *fn;
|
||
+{
|
||
+ void *r = (void *) malloc(n);
|
||
+ if(r == NULL)
|
||
+ pi_memory_error("malloc", fn);
|
||
+ return r;
|
||
+}
|
||
+
|
||
+static void *pi_realloc(p, n, fn)
|
||
+ void *p;
|
||
+ size_t n;
|
||
+ char *fn;
|
||
+{
|
||
+ void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n);
|
||
+ if(r == NULL)
|
||
+ pi_memory_error("realloc", fn);
|
||
+ return r;
|
||
+}
|
||
+#endif /* HAVE_PI */
|
||
diff -u -r --new-file xv-3.10a.orig/xvpic.c xv-3.10a/xvpic.c
|
||
--- xv-3.10a.orig/xvpic.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvpic.c 2005-04-18 00:57:08.000000000 -0500
|
||
@@ -0,0 +1,1285 @@
|
||
+/*
|
||
+ * xvpic.c - load routine for `PIC' format pictures.
|
||
+ *
|
||
+ * The `PIC' format is used by many Japanese personal computer users.
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+#include <setjmp.h>
|
||
+
|
||
+#ifdef HAVE_PIC
|
||
+
|
||
+typedef unsigned short data16;
|
||
+typedef unsigned int data32;
|
||
+
|
||
+struct pic_info {
|
||
+ jmp_buf jmp;
|
||
+ FILE *fp;
|
||
+ struct {
|
||
+ int rest;
|
||
+ byte cur;
|
||
+ }bs;
|
||
+ long fsize;
|
||
+ int type, mode;
|
||
+ int width, height;
|
||
+ float aspect;
|
||
+ int cbits;
|
||
+ int cmapped;
|
||
+ byte *cmap;
|
||
+ int cached;
|
||
+ struct cache_t {
|
||
+ int newest;
|
||
+ struct cachenode_t {
|
||
+ data32 dat;
|
||
+ int newer, older;
|
||
+ } *node;
|
||
+ } cache;
|
||
+ int g_bits, r_bits, b_bits, i_bits;
|
||
+ int inv_gr;
|
||
+ int tiled256;
|
||
+ int numcols;
|
||
+ int writing_grey;
|
||
+ data32 *data;
|
||
+};
|
||
+
|
||
+static void pic_open_file PARM((struct pic_info*,char*));
|
||
+static void pic_check_id PARM((struct pic_info*));
|
||
+static void pic_read_comment PARM((struct pic_info*, char**));
|
||
+static void pic_read_header PARM((struct pic_info*));
|
||
+static void pic_expand_data PARM((struct pic_info*));
|
||
+static int pic_expanding_read_len PARM((struct pic_info*));
|
||
+static data32 pic_expanding_read_color PARM((struct pic_info*));
|
||
+static void pic_expanding_read_chain
|
||
+ PARM((struct pic_info*, int, int, data32));
|
||
+static void pic_make_xvpic
|
||
+ PARM((struct pic_info*, byte**, byte*, byte*, byte*));
|
||
+
|
||
+static void pic_write_id PARM((struct pic_info*));
|
||
+static void pic_write_comment PARM((struct pic_info*, char*));
|
||
+static void pic_write_header PARM((struct pic_info*));
|
||
+static void pic_write_palette
|
||
+ PARM((struct pic_info*, byte*, byte*, byte*));
|
||
+static void pic_make_sparse_data PARM((struct pic_info*, byte*));
|
||
+static void pic_write_data PARM((struct pic_info*));
|
||
+static void pic_write_length PARM((struct pic_info*, data32));
|
||
+static void pic_write_color PARM((struct pic_info*, data32));
|
||
+static void pic_write_chain
|
||
+ PARM((struct pic_info*, int, int, data32));
|
||
+
|
||
+static data32 pic_read_rgb PARM((struct pic_info*));
|
||
+static data32 pic_read_color_code PARM((struct pic_info*));
|
||
+static void pic_write_rgb PARM((struct pic_info*, data32));
|
||
+static void pic_write_color_code PARM((struct pic_info*, data32));
|
||
+
|
||
+static void pic_cache_init PARM((struct pic_info*));
|
||
+static data32 pic_cache_get_value PARM((struct pic_info*, int));
|
||
+static void pic_cache_add_value PARM((struct pic_info*, data32));
|
||
+static int pic_cache_lookup PARM((struct pic_info*, data32));
|
||
+
|
||
+static data32 pic_read_bits PARM((struct pic_info*, int));
|
||
+static void pic_write_bits PARM((struct pic_info*, data32, int));
|
||
+static byte pic_pad_bit PARM((int, data32));
|
||
+
|
||
+static void pic_init_info PARM((struct pic_info*));
|
||
+static void pic_cleanup_pic_info PARM((struct pic_info*, int));
|
||
+static void pic_cleanup_pinfo PARM((PICINFO*));
|
||
+static void pic_memory_error PARM((char*, char*));
|
||
+static void pic_error PARM((struct pic_info*, int));
|
||
+static void pic_file_error PARM((struct pic_info*, int));
|
||
+static void pic_file_warning PARM((struct pic_info*, int));
|
||
+static void pic_show_pic_info PARM((struct pic_info*));
|
||
+static void *pic_malloc PARM((size_t, char*));
|
||
+static void *pic_realloc PARM((void*, size_t, char*));
|
||
+
|
||
+
|
||
+static char *pic_id = "PIC";
|
||
+
|
||
+/* Error Messages */
|
||
+static char *pic_msgs[] = {
|
||
+ NULL,
|
||
+#define PIC_OPEN 1
|
||
+ "can't open file.",
|
||
+#define PIC_CORRUPT 2
|
||
+ "file corrupted.",
|
||
+#define PIC_FORMAT 3
|
||
+ "not PIC format.",
|
||
+#define PIC_SUPPORT 4
|
||
+ "unsupported type.",
|
||
+#define PIC_COMMENT 5
|
||
+ "can't read comment.",
|
||
+#define PIC_TYPE 6
|
||
+ "bad machine type.",
|
||
+#define PIC_MODE 7
|
||
+ "bad machine-dependent mode.",
|
||
+#define PIC_NUM_COLORS 8
|
||
+ "bad number of colors.",
|
||
+#define PIC_SIZE 9
|
||
+ "bad size.",
|
||
+#define PIC_ASPECT 10
|
||
+ "bad aspect.",
|
||
+#define PIC_WRITE 11
|
||
+ "write failed.",
|
||
+};
|
||
+
|
||
+#define H4(b) (((b) >> 4) & 0x0f)
|
||
+#define L4(b) ( (b) & 0x0f)
|
||
+
|
||
+
|
||
+/* The main routine to load a PIC file. */
|
||
+int LoadPIC(fname, pinfo)
|
||
+ char *fname;
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ int e;
|
||
+ struct pic_info pic;
|
||
+ char buf[128];
|
||
+
|
||
+ if(DEBUG) fputs("LoadPIC:\n", stderr);
|
||
+
|
||
+ pic_init_info(&pic);
|
||
+
|
||
+ pinfo->comment = NULL;
|
||
+ if((e = setjmp(pic.jmp)) != 0){
|
||
+ /* When an error occurs, comes here. */
|
||
+ pic_cleanup_pic_info(&pic, 0);
|
||
+ pic_cleanup_pinfo(pinfo);
|
||
+ if(DEBUG) fputs("\n", stderr);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ pic_open_file(&pic, fname);
|
||
+ pic_check_id(&pic);
|
||
+ pic_read_comment(&pic, &pinfo->comment);
|
||
+ pic_read_header(&pic);
|
||
+ pic_expand_data(&pic);
|
||
+ pic_make_xvpic(&pic, &pinfo->pic, pinfo->r, pinfo->g, pinfo->b);
|
||
+
|
||
+ pinfo->w = pic.width;
|
||
+ if(pic.tiled256)
|
||
+ pinfo->h = pic.height * 2;
|
||
+ else
|
||
+ pinfo->h = pic.height;
|
||
+ pinfo->normw = pinfo->w;
|
||
+ pinfo->normh = pinfo->h;
|
||
+ pinfo->type = pic.cmapped ? PIC8 : PIC24;
|
||
+ pinfo->frmType = F_PIC;
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ strcpy(pinfo->fullInfo, "PIC");
|
||
+ switch(pic.type){
|
||
+ case 0x0:
|
||
+ strcat(pinfo->fullInfo, ", X68k");
|
||
+ break;
|
||
+ case 0x1:
|
||
+ strcat(pinfo->fullInfo, ", PC-88VA");
|
||
+ if(pic.mode & 1)
|
||
+ strcat(pinfo->fullInfo, ", HR");
|
||
+ if(pic.mode & 2)
|
||
+ strcat(pinfo->fullInfo, ", tiled 256");
|
||
+ break;
|
||
+ case 0x2:
|
||
+ strcat(pinfo->fullInfo, ", FM-TOWNS");
|
||
+ if(pic.mode == 0x5){
|
||
+ strcat(pinfo->fullInfo, ", low-resolution");
|
||
+ }else{
|
||
+ strcat(pinfo->fullInfo, ", high-resolution");
|
||
+ }
|
||
+ break;
|
||
+ case 0x3:
|
||
+ strcat(pinfo->fullInfo, ", Macintosh");
|
||
+ break;
|
||
+ case 0xf:
|
||
+ ;
|
||
+ }
|
||
+ sprintf(buf, " (%ld bytes)", pic.fsize);
|
||
+ strcat(pinfo->fullInfo, buf);
|
||
+ sprintf(pinfo->shrtInfo, "%dx%d(aspect %4.2f) PIC.",
|
||
+ pinfo->w, pinfo->h, pic.aspect);
|
||
+ if (!nopicadjust)
|
||
+ normaspect = pic.aspect;
|
||
+
|
||
+ pic_cleanup_pic_info(&pic, 0);
|
||
+ if(DEBUG) fputs("\n", stderr);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static void pic_open_file(pi, fname)
|
||
+ struct pic_info *pi;
|
||
+ char *fname;
|
||
+{
|
||
+ if((pi->fp = fopen(fname, "rb")) == NULL)
|
||
+ pic_file_error(pi, PIC_OPEN);
|
||
+ fseek(pi->fp, (size_t) 0, SEEK_END);
|
||
+ pi->fsize = ftell(pi->fp);
|
||
+ fseek(pi->fp, (size_t) 0, SEEK_SET);
|
||
+}
|
||
+
|
||
+static void pic_check_id(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ char buf[3];
|
||
+ if(fread(buf, (size_t) 3, (size_t) 1, pi->fp) != 1)
|
||
+ pic_file_error(pi, PIC_CORRUPT);
|
||
+ if(strncmp(buf, pic_id, (size_t) 3) != 0)
|
||
+ pic_error(pi, PIC_FORMAT);
|
||
+}
|
||
+
|
||
+static void pic_read_comment(pi, comm)
|
||
+ struct pic_info *pi;
|
||
+ char **comm;
|
||
+{
|
||
+ /* The comment field is like:
|
||
+ * comment-string ^Z dummy \0 \0
|
||
+ */
|
||
+ int max = -1, i = 0;
|
||
+ int c;
|
||
+
|
||
+ while(1){
|
||
+ if((c = fgetc(pi->fp)) == EOF)
|
||
+ pic_file_error(pi, PIC_CORRUPT);
|
||
+ if(c == '\032') /* 0x1a, '^Z' */
|
||
+ break;
|
||
+ if(max < i){
|
||
+ max += 32;
|
||
+ *comm = pic_realloc(*comm, (size_t) max + 1, "pic_read_comment#1");
|
||
+ }
|
||
+ (*comm)[i++] = c;
|
||
+ }
|
||
+
|
||
+ if(max < i){
|
||
+ max++;
|
||
+ *comm = pic_realloc(*comm, (size_t) max + 1, "pic_read_comment#2");
|
||
+ }
|
||
+ (*comm)[i] = '\0';
|
||
+
|
||
+ while((c = fgetc(pi->fp)) != '\0'){ /* skip the dummy area */
|
||
+ if(c == EOF)
|
||
+ pic_file_error(pi, PIC_CORRUPT);
|
||
+ }
|
||
+
|
||
+ if(fgetc(pi->fp) != '\0') /* check the reserved byte */
|
||
+ pic_error(pi, PIC_SUPPORT);
|
||
+}
|
||
+
|
||
+static void pic_read_header(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ pi->mode = pic_read_bits(pi, 4);
|
||
+ pi->type = pic_read_bits(pi, 4);
|
||
+ pi->cbits = pic_read_bits(pi, 16);
|
||
+ pi->width = pic_read_bits(pi, 16);
|
||
+ pi->height = pic_read_bits(pi, 16);
|
||
+
|
||
+ /* machine-dependent setup. */
|
||
+ switch(pi->type){
|
||
+ case 0x0: /* X68K */
|
||
+ if(pi->mode != 0)
|
||
+ pic_error(pi, PIC_MODE);
|
||
+ switch(pi->cbits){
|
||
+ case 4:
|
||
+ pi->aspect = 1.0;
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 5;
|
||
+ pi->i_bits = 1;
|
||
+ pi->cmapped = 1;
|
||
+ break;
|
||
+
|
||
+ case 8:
|
||
+ pi->aspect = 4.0 / 3.0;
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 5;
|
||
+ pi->i_bits = 1;
|
||
+ pi->cmapped = 1;
|
||
+ break;
|
||
+
|
||
+ case 15:
|
||
+ pi->aspect = 4.0 / 3.0;
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 5;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ case 16:
|
||
+ pi->aspect = 4.0 / 3.0;
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 5;
|
||
+ pi->i_bits = 1;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ pic_error(pi, PIC_NUM_COLORS);
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case 0x1: /* PC-88VA */
|
||
+ if(pi->height > 1000)
|
||
+ pic_error(pi, PIC_SIZE);
|
||
+ switch(pi->width * 1000 + pi->height){
|
||
+ case 640400:
|
||
+ case 640204:
|
||
+ case 640200:
|
||
+ case 320408:
|
||
+ case 320400:
|
||
+ case 320200:
|
||
+ break;
|
||
+ default:
|
||
+ pic_error(pi, PIC_SIZE);
|
||
+ }
|
||
+ pi->aspect = 400.0 / pi->height;
|
||
+ pi->aspect *= pi->width / 640.0;
|
||
+ if(pi->mode & 0x1) /* HR mode */
|
||
+ pi->aspect *= 2.0;
|
||
+ if(pi->mode & 0x2){ /* tiled 256 format */
|
||
+ if(pi->cbits != 16)
|
||
+ pic_error(pi, PIC_NUM_COLORS);
|
||
+ pi->tiled256 = 1;
|
||
+ }
|
||
+ switch(pi->cbits){
|
||
+ case 8:
|
||
+ pi->g_bits = pi->r_bits = 3;
|
||
+ pi->b_bits = 2;
|
||
+ break;
|
||
+
|
||
+ case 12:
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 4;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ case 16:
|
||
+ pi->g_bits = 6;
|
||
+ pi->r_bits = pi->b_bits = 5;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ pic_error(pi, PIC_NUM_COLORS);
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case 0x2: /* FM-TOWNS */
|
||
+ if(pi->cbits != 15)
|
||
+ pic_error(pi, PIC_NUM_COLORS);
|
||
+ switch(pi->mode){
|
||
+ case 0x5:
|
||
+ case 0xc:
|
||
+ break;
|
||
+ default:
|
||
+ pic_error(pi, PIC_MODE);
|
||
+ }
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 5;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ case 0x3: /* MAC */
|
||
+ if(pi->cbits != 15)
|
||
+ pic_error(pi, PIC_NUM_COLORS);
|
||
+ pi->r_bits = pi->g_bits = pi->b_bits = 5;
|
||
+ pi->inv_gr = 1;
|
||
+ break;
|
||
+
|
||
+ case 0xf: /* misc */
|
||
+ {
|
||
+ byte ah, al;
|
||
+
|
||
+ switch(pi->mode){
|
||
+ case 0x0:
|
||
+ break;
|
||
+ case 0x1:
|
||
+ pi->aspect = 4.0 / 3.0;
|
||
+ break;
|
||
+ case 0xf:
|
||
+ break;
|
||
+ default:
|
||
+ pic_error(pi, PIC_MODE);
|
||
+ }
|
||
+ pic_read_bits(pi, 16); /* x */
|
||
+ pic_read_bits(pi, 16); /* y */
|
||
+ ah = pic_read_bits(pi, 8);
|
||
+ al = pic_read_bits(pi, 8);
|
||
+ if(ah > 0 && al > 0)
|
||
+ pi->aspect = (float) al / (int) ah;
|
||
+ else if(pi->mode == 0xf)
|
||
+ pic_error(pi, PIC_ASPECT);
|
||
+ switch(pi->cbits){
|
||
+ case 4:
|
||
+ case 8:
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = pic_read_bits(pi, 8);
|
||
+ pi->cmapped = 1;
|
||
+ break;
|
||
+
|
||
+ case 12:
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 4;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ case 15:
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 5;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ case 16:
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 5;
|
||
+ pi->i_bits = 1;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ case 24:
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = 8;
|
||
+ pi->cached = 1;
|
||
+ break;
|
||
+
|
||
+ case 32:
|
||
+ pic_error(pi, PIC_SUPPORT);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ pic_error(pi, PIC_NUM_COLORS);
|
||
+ }
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ pic_error(pi, PIC_TYPE);
|
||
+ }
|
||
+
|
||
+ pi->numcols = 1 << pi->cbits;
|
||
+
|
||
+ /* read palette data */
|
||
+ if(pi->cmapped){
|
||
+ int i;
|
||
+ pi->cmap = pic_malloc((size_t) 3 * pi->numcols, "pic_read_header#1");
|
||
+ for(i = 0; i < pi->numcols; i++){
|
||
+ data32 c = pic_read_rgb(pi);
|
||
+ pi->cmap[i * 3 ] = c >> 16 & 0xff;
|
||
+ pi->cmap[i * 3 + 1] = c >> 8 & 0xff;
|
||
+ pi->cmap[i * 3 + 2] = c & 0xff;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* setup color code cache */
|
||
+ if(pi->cached)
|
||
+ pic_cache_init(pi);
|
||
+
|
||
+
|
||
+ pi->data = pic_malloc(sizeof(data32) * pi->width * pi->height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "pic_read_header#2");
|
||
+ {
|
||
+ int i;
|
||
+ for(i = 0; i < pi->width * pi->height; i++)
|
||
+ pi->data[i] = 0xffffffff;
|
||
+ }
|
||
+
|
||
+ if(DEBUG)
|
||
+ pic_show_pic_info(pi);
|
||
+}
|
||
+
|
||
+/* The main routine to expand a PIC file. */
|
||
+static void pic_expand_data(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ int cnt;
|
||
+ data32 c;
|
||
+ pi->data[0] = c = 0;
|
||
+ for(cnt = -1; cnt < pi->width * pi->height; ){
|
||
+ int len = pic_expanding_read_len(pi);
|
||
+ cnt += len;
|
||
+ if(cnt < pi->width * pi->height){
|
||
+ int x = cnt % pi->width;
|
||
+ int y = cnt / pi->width;
|
||
+ data32 c = pic_expanding_read_color(pi);
|
||
+ pic_expanding_read_chain(pi, x, y, c);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static int pic_expanding_read_len(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ int len;
|
||
+ byte bits;
|
||
+ for(len = 2, bits = 1; pic_read_bits(pi, 1) == 1; bits++)
|
||
+ len <<= 1;
|
||
+ return len - 1 + pic_read_bits(pi, bits);
|
||
+}
|
||
+
|
||
+static data32 pic_expanding_read_color(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ if(pi->cached){
|
||
+ byte b = pic_read_bits(pi, 1);
|
||
+ if(b){
|
||
+ return pic_cache_get_value(pi, (int) pic_read_bits(pi, 7));
|
||
+ }else{
|
||
+ data32 c = pic_read_color_code(pi);
|
||
+ pic_cache_add_value(pi, c);
|
||
+ return c;
|
||
+ }
|
||
+ }
|
||
+ return pic_read_color_code(pi);
|
||
+}
|
||
+
|
||
+static void pic_expanding_read_chain(pi, x, y, c)
|
||
+ struct pic_info *pi;
|
||
+ int x, y;
|
||
+ data32 c;
|
||
+{
|
||
+ pi->data[y * pi->width + x] = c;
|
||
+ if(pic_read_bits(pi, 1) == 1){
|
||
+ int fin = 0;
|
||
+ while(!fin){
|
||
+ switch(pic_read_bits(pi, 2)){
|
||
+ case 1: /* left */
|
||
+ pi->data[(++y) * pi->width + (--x)] = c;
|
||
+ break;
|
||
+ case 2: /* middle */
|
||
+ pi->data[(++y) * pi->width + x ] = c;
|
||
+ break;
|
||
+ case 3: /* right */
|
||
+ pi->data[(++y) * pi->width + (++x)] = c;
|
||
+ break;
|
||
+ case 0: /* far or nothing */
|
||
+ if(pic_read_bits(pi, 1) == 0)
|
||
+ fin = 1;
|
||
+ else{
|
||
+ if(pic_read_bits(pi, 1) == 0)
|
||
+ pi->data[(++y) * pi->width + (x -= 2)] = c;
|
||
+ else
|
||
+ pi->data[(++y) * pi->width + (x += 2)] = c;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Make a picture from the expanded data.
|
||
+ */
|
||
+static void pic_make_xvpic(pi, xp, rp, gp, bp)
|
||
+ struct pic_info *pi;
|
||
+ byte **xp, *rp, *gp, *bp;
|
||
+{
|
||
+ if(pi->cmapped){
|
||
+ if(pi->tiled256)
|
||
+ *xp = pic_malloc((size_t) pi->width * pi->height * 2, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "pic_make_xvpic#1");
|
||
+ else
|
||
+ *xp = pic_malloc((size_t) pi->width * pi->height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "pic_make_xvpic#2");
|
||
+ }else
|
||
+ *xp = pic_malloc((size_t) pi->width * pi->height * 3, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "pic_make_xvpic#3");
|
||
+
|
||
+ if(pi->cmapped){
|
||
+ int i;
|
||
+
|
||
+ for(i = 0; i < pi->numcols; i++){
|
||
+ rp[i] = pi->cmap[i * 3 ];
|
||
+ gp[i] = pi->cmap[i * 3 + 1];
|
||
+ bp[i] = pi->cmap[i * 3 + 2];
|
||
+ }
|
||
+
|
||
+ if(pi->tiled256){
|
||
+ int pic_idx = 0, dat_idx;
|
||
+ data16 col = 0;
|
||
+ for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){
|
||
+ if(pi->data[dat_idx] != 0xffffffff)
|
||
+ col = pi->data[dat_idx];
|
||
+ (*xp)[pic_idx++] = col & 0xff;
|
||
+ (*xp)[pic_idx++] = col >> 8 & 0xff;
|
||
+ dat_idx++;
|
||
+ }
|
||
+ }else{
|
||
+ int pic_idx = 0, dat_idx;
|
||
+ byte col = 0;
|
||
+ for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){
|
||
+ if(pi->data[dat_idx] != 0xffffffff)
|
||
+ col = pi->data[dat_idx];
|
||
+ (*xp)[pic_idx++] = col;
|
||
+ }
|
||
+ }
|
||
+ }else{
|
||
+ int pic_idx = 0, dat_idx;
|
||
+ byte r = 0, g = 0, b = 0;
|
||
+ for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){
|
||
+ if(pi->data[dat_idx] != 0xffffffff){
|
||
+ data32 col = pi->data[dat_idx];
|
||
+ r = col >> 16 & 0xff;
|
||
+ g = col >> 8 & 0xff;
|
||
+ b = col & 0xff;
|
||
+ }
|
||
+ (*xp)[pic_idx++] = r;
|
||
+ (*xp)[pic_idx++] = g;
|
||
+ (*xp)[pic_idx++] = b;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/* The main routine to write PIC file. */
|
||
+int WritePIC(fp, pic0, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
|
||
+ comment)
|
||
+ FILE *fp;
|
||
+ byte *pic0;
|
||
+ int ptype, w, h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int numcols, colorstyle;
|
||
+ char *comment;
|
||
+{
|
||
+ struct pic_info pic;
|
||
+ int e;
|
||
+
|
||
+ if(DEBUG) fputs("WritePIC:\n", stderr);
|
||
+
|
||
+ pic_init_info(&pic);
|
||
+ pic.fp = fp;
|
||
+ pic.width = w;
|
||
+ pic.height = h;
|
||
+ pic.writing_grey = (colorstyle == F_GREYSCALE);
|
||
+ if(ptype != PIC24){ /* PIC8 */
|
||
+ pic.cmapped = 1;
|
||
+ pic.cached = 0;
|
||
+ pic.cbits = 8;
|
||
+ pic.g_bits =
|
||
+ pic.r_bits =
|
||
+ pic.b_bits = 8;
|
||
+ pic.i_bits = 0;
|
||
+ pic.numcols = numcols;
|
||
+ }else{ /* PIC24 */
|
||
+ pic.cmapped = 0;
|
||
+ pic.cached = 1;
|
||
+ pic.cbits = 24;
|
||
+ pic.g_bits =
|
||
+ pic.r_bits =
|
||
+ pic.b_bits = 8;
|
||
+ pic.i_bits = 0;
|
||
+ pic.numcols = 1 << 24;
|
||
+ pic_cache_init(&pic);
|
||
+ }
|
||
+
|
||
+ if((e = setjmp(pic.jmp)) != 0){
|
||
+ /* When an error occurs while writing, comes here. */
|
||
+ pic_cleanup_pic_info(&pic, 1);
|
||
+ if(DEBUG) fputs("\n", stderr);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ pic_write_id(&pic);
|
||
+ pic_write_comment(&pic, comment);
|
||
+ pic_write_header(&pic);
|
||
+ if(pic.cmapped)
|
||
+ pic_write_palette(&pic, rmap, gmap, bmap);
|
||
+ pic_make_sparse_data(&pic, pic0);
|
||
+ pic_write_data(&pic);
|
||
+ pic_write_bits(&pic, 0, 8);
|
||
+
|
||
+ pic_cleanup_pic_info(&pic, 1);
|
||
+ if(DEBUG) fputs("\n", stderr);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void pic_write_id(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ if(fwrite("PIC", (size_t) 3, (size_t) 1, pi->fp) != 1)
|
||
+ pic_file_error(pi, PIC_WRITE);
|
||
+}
|
||
+
|
||
+static void pic_write_comment(pi, comm)
|
||
+ struct pic_info *pi;
|
||
+ char *comm;
|
||
+{
|
||
+ if(comm){
|
||
+ while(*comm){
|
||
+ int c = *comm;
|
||
+ if(c == '\032')
|
||
+ c = ' ';
|
||
+ if(fputc(*comm, pi->fp) == EOF)
|
||
+ pic_file_error(pi, PIC_WRITE);
|
||
+ comm++;
|
||
+ }
|
||
+ }
|
||
+ /* write ^Z, 0, and reserved. */
|
||
+ if(fwrite("\032\0\0", (size_t)3, (size_t) 1, pi->fp) != 1)
|
||
+ pic_file_error(pi, PIC_WRITE);
|
||
+}
|
||
+
|
||
+static void pic_write_header(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ if(DEBUG) pic_show_pic_info(pi);
|
||
+ pic_write_bits(pi, (data32) 0, 4); /* mode: 1:1 */
|
||
+ pic_write_bits(pi, (data32) 0xf, 4); /* type: misc */
|
||
+ pic_write_bits(pi, (data32) pi->cbits, 16); /* bits */
|
||
+ pic_write_bits(pi, (data32) pi->width, 16); /* width */
|
||
+ pic_write_bits(pi, (data32) pi->height, 16); /* height */
|
||
+ pic_write_bits(pi, (data32) 0xffff, 16); /* x: unused */
|
||
+ pic_write_bits(pi, (data32) 0xffff, 16); /* y: unused */
|
||
+ pic_write_bits(pi, (data32) 0x0101, 16); /* real aspect */
|
||
+}
|
||
+
|
||
+static void pic_write_palette(pi, r, g, b)
|
||
+ struct pic_info *pi;
|
||
+ byte *r, *g, *b;
|
||
+{
|
||
+ int i;
|
||
+ data32 rgb = 0;
|
||
+ pic_write_bits(pi, (data32) pi->g_bits, 8);
|
||
+ for(i = 0; i < pi->numcols; i++){
|
||
+ rgb = (data32) *r++ << 16 | (data32) *g++ << 8 | (data32) *b++;
|
||
+ pic_write_rgb(pi, rgb);
|
||
+ }
|
||
+ for( ; i < 256; i++)
|
||
+ pic_write_rgb(pi, rgb);
|
||
+}
|
||
+
|
||
+static void pic_make_sparse_data(pi, dat)
|
||
+ struct pic_info *pi;
|
||
+ byte *dat;
|
||
+{
|
||
+ int i;
|
||
+ data32 c;
|
||
+
|
||
+ pi->data = pic_malloc(sizeof(data32) * pi->width * pi->height, // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ "pic_make_sparse_data");
|
||
+
|
||
+ if(pi->cmapped){
|
||
+ c = 0;
|
||
+ for(i = 0; i < pi->width * pi->height; i++){
|
||
+ if(c != dat[i])
|
||
+ c = pi->data[i] = dat[i];
|
||
+ else
|
||
+ pi->data[i] = 0xffffffff;
|
||
+ }
|
||
+ }else{
|
||
+ int j = 0;
|
||
+ c = 0;
|
||
+ for(i = 0; i < pi->width * pi->height; i++){
|
||
+ data32 r, g, b, t;
|
||
+ r = dat[j++];
|
||
+ g = dat[j++];
|
||
+ b = dat[j++];
|
||
+ t = r << 16 | g << 8 | b;
|
||
+ if(c != t)
|
||
+ c = pi->data[i] = t;
|
||
+ else
|
||
+ pi->data[i] = 0xffffffff;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic_write_data(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ int i;
|
||
+ int max = pi->width * pi->height;
|
||
+ data32 c = 0;
|
||
+
|
||
+ i = -1;
|
||
+ while(i < max){
|
||
+ int j;
|
||
+ for(j = i + 1; j < max; j++){
|
||
+ if(pi->data[j] != 0xffffffff)
|
||
+ break;
|
||
+ }
|
||
+ pic_write_length(pi, (data32) j - i);
|
||
+ i = j;
|
||
+ if(i < max){
|
||
+ pic_write_color(pi, c = pi->data[i]);
|
||
+ pic_write_chain(pi, i % pi->width, i / pi->width, c);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic_write_length(pi, len)
|
||
+ struct pic_info *pi;
|
||
+ data32 len;
|
||
+{
|
||
+ int bits = 0; /* leading 1's */
|
||
+ int max = 2;
|
||
+
|
||
+ while(len > max){
|
||
+ max = (max + 1) * 2;
|
||
+ bits++;
|
||
+ }
|
||
+ pic_write_bits(pi, 0xffffffff, bits);
|
||
+ pic_write_bits(pi, 0, 1);
|
||
+ pic_write_bits(pi, len - max / 2, bits + 1);
|
||
+}
|
||
+
|
||
+static void pic_write_color(pi, c)
|
||
+ struct pic_info *pi;
|
||
+ data32 c;
|
||
+{
|
||
+ if(pi->cached){
|
||
+ int idx = pic_cache_lookup(pi, c);
|
||
+ if(idx < 0){ /* not found */
|
||
+ pic_write_bits(pi, 0, 1);
|
||
+ pic_write_color_code(pi, c);
|
||
+ pic_cache_add_value(pi, c);
|
||
+ }else{ /* found */
|
||
+ pic_write_bits(pi, (data32) 0xffffffff, 1);
|
||
+ pic_write_bits(pi, (data32) idx, 7);
|
||
+ }
|
||
+ }else
|
||
+ pic_write_color_code(pi, c);
|
||
+}
|
||
+
|
||
+static void pic_write_chain(pi, x, y, c)
|
||
+ struct pic_info *pi;
|
||
+ int x, y;
|
||
+ data32 c;
|
||
+{
|
||
+ int ctr = (y + 1) * pi->width + x;
|
||
+
|
||
+ if(y < pi->height - 1 &&
|
||
+ ( pi->data[ctr ] == c ||
|
||
+ (x > 0 && pi->data[ctr - 1] == c) ||
|
||
+ (x < pi->width - 1 && pi->data[ctr + 1] == c) ||
|
||
+ (x > 1 && pi->data[ctr - 2] == c) ||
|
||
+ (x < pi->width - 2 && pi->data[ctr + 2] == c))){
|
||
+ pic_write_bits(pi, 1, 1);
|
||
+ while(++y < pi->height){
|
||
+ if(pi->data[ctr] == c){ /* center */
|
||
+ pic_write_bits(pi, 2, 2);
|
||
+ pi->data[ctr] = 0xffffffff;
|
||
+ ctr += pi->width;
|
||
+ }else if(x > 0 && pi->data[ctr - 1] == c){ /* left */
|
||
+ pic_write_bits(pi, 1, 2);
|
||
+ pi->data[ctr - 1] = 0xffffffff;
|
||
+ ctr += pi->width - 1;
|
||
+ }else if(x < pi->width - 1 && pi->data[ctr + 1] == c){/* right */
|
||
+ pic_write_bits(pi, 3, 2);
|
||
+ pi->data[ctr + 1] = 0xffffffff;
|
||
+ ctr += pi->width + 1;
|
||
+ }else if(x > 1 && pi->data[ctr - 2] == c){ /* 2-left */
|
||
+ pic_write_bits(pi, 2, 4);
|
||
+ pi->data[ctr - 2] = 0xffffffff;
|
||
+ ctr += pi->width - 2;
|
||
+ }else if(x < pi->width - 2 && pi->data[ctr + 2] == c){/* 2-right */
|
||
+ pic_write_bits(pi, 3, 4);
|
||
+ pi->data[ctr + 2] = 0xffffffff;
|
||
+ ctr += pi->width + 2;
|
||
+ }else /* nothing */
|
||
+ break;
|
||
+ }
|
||
+ pic_write_bits(pi, 0, 3);
|
||
+ }else
|
||
+ pic_write_bits(pi, 0, 1);
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ * These 4 functions read or write a color.
|
||
+ *
|
||
+ * pic_read_rgb:
|
||
+ * reads an RGB. Each bit length is [rgb]_bits, but
|
||
+ * it is expanded to 8bits when returned.
|
||
+ *
|
||
+ * pic_read_color_code:
|
||
+ * reads a color code, whose length is cbits.
|
||
+ * It is the index to the colormap or RGB itself.
|
||
+ *
|
||
+ * pic_write_rgb:
|
||
+ * writes an RGB value.
|
||
+ *
|
||
+ * pic_write_color_code:
|
||
+ * writes a color code.
|
||
+ */
|
||
+static data32 pic_read_rgb(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ int rb = pi->r_bits, gb = pi->g_bits, bb = pi->b_bits;
|
||
+ byte r, g, b;
|
||
+ if(pi->inv_gr){
|
||
+ r = pic_read_bits(pi, rb);
|
||
+ g = pic_read_bits(pi, gb);
|
||
+ }else{
|
||
+ g = pic_read_bits(pi, gb);
|
||
+ r = pic_read_bits(pi, rb);
|
||
+ }
|
||
+ b = pic_read_bits(pi, bb);
|
||
+ if(pi->i_bits){
|
||
+ byte i;
|
||
+ i = pic_read_bits(pi, pi->i_bits);
|
||
+ r = r << pi->i_bits | i;
|
||
+ g = g << pi->i_bits | i;
|
||
+ b = b << pi->i_bits | i;
|
||
+ rb += pi->i_bits;
|
||
+ gb += pi->i_bits;
|
||
+ bb += pi->i_bits;
|
||
+ }
|
||
+ r = pic_pad_bit(rb, r);
|
||
+ g = pic_pad_bit(gb, g);
|
||
+ b = pic_pad_bit(bb, b);
|
||
+
|
||
+ return (data32) r << 16 | (data32) g << 8 | (data32) b;
|
||
+}
|
||
+
|
||
+static data32 pic_read_color_code(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ if(pi->cmapped)
|
||
+ return pic_read_bits(pi, pi->cbits);
|
||
+ return pic_read_rgb(pi);
|
||
+}
|
||
+
|
||
+static void pic_write_rgb(pi, rgb)
|
||
+ struct pic_info *pi;
|
||
+ data32 rgb;
|
||
+{
|
||
+ byte r = rgb >> 16;
|
||
+ byte g = rgb >> 8;
|
||
+ byte b = rgb;
|
||
+ if(pi->writing_grey)
|
||
+ r = g = b = MONO(r, g, b);
|
||
+ pic_write_bits(pi, g, pi->g_bits);
|
||
+ pic_write_bits(pi, r, pi->r_bits);
|
||
+ pic_write_bits(pi, b, pi->b_bits);
|
||
+}
|
||
+
|
||
+static void pic_write_color_code(pi, code)
|
||
+ struct pic_info *pi;
|
||
+ data32 code;
|
||
+{
|
||
+ if(pi->cmapped){
|
||
+ pic_write_bits(pi, code, pi->cbits);
|
||
+ }else{
|
||
+ pic_write_rgb(pi, code);
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ * These pic_cache_* functions are an implementation of the color cache.
|
||
+ *
|
||
+ * pic_cache_init:
|
||
+ * initializes the cache.
|
||
+ *
|
||
+ * pic_cache_get_value:
|
||
+ * gets a color indexed by the argument `idx'.
|
||
+ * It updates the `most recently used' time.
|
||
+ *
|
||
+ * pic_cache_add_value:
|
||
+ * adds a color to the top of the cache list.
|
||
+ */
|
||
+static void pic_cache_init(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ int i;
|
||
+ pi->cache.node = pic_malloc(sizeof(struct cachenode_t) * 128,
|
||
+ "pic_cache_init");
|
||
+ for(i = 0; i < 128; i++){
|
||
+ pi->cache.node[i].newer = i + 1;
|
||
+ pi->cache.node[i].older = i - 1;
|
||
+ pi->cache.node[i].dat = 0;
|
||
+ }
|
||
+ pi->cache.node[ 0].older = 127;
|
||
+ pi->cache.node[127].newer = 0;
|
||
+ pi->cache.newest = 0;
|
||
+}
|
||
+
|
||
+static data32 pic_cache_get_value(pi, idx)
|
||
+ struct pic_info *pi;
|
||
+ int idx;
|
||
+{
|
||
+ struct cachenode_t *p = pi->cache.node;
|
||
+ int n = pi->cache.newest;
|
||
+ if(n != idx){
|
||
+ p[p[idx].newer].older = p[idx].older;
|
||
+ p[p[idx].older].newer = p[idx].newer;
|
||
+
|
||
+ p[p[n].newer].older = idx;
|
||
+ p[idx].newer = p[n].newer;
|
||
+ p[n].newer = idx;
|
||
+ p[idx].older = n;
|
||
+
|
||
+ pi->cache.newest = idx;
|
||
+ }
|
||
+ return pi->cache.node[idx].dat;
|
||
+}
|
||
+
|
||
+static void pic_cache_add_value(pi, dat)
|
||
+ struct pic_info *pi;
|
||
+ data32 dat;
|
||
+{
|
||
+ pi->cache.newest = pi->cache.node[pi->cache.newest].newer;
|
||
+ pi->cache.node[pi->cache.newest].dat = dat;
|
||
+}
|
||
+
|
||
+static int pic_cache_lookup(pi, dat)
|
||
+ struct pic_info *pi;
|
||
+ data32 dat;
|
||
+{
|
||
+ int i;
|
||
+ for(i = 0; i < 128; i++){
|
||
+ if(pi->cache.node[i].dat == dat){
|
||
+ pic_cache_get_value(pi, i);
|
||
+ return i;
|
||
+ }
|
||
+ }
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ * These pic_{read,write}_bits functions access the bit stream.
|
||
+ * pic_read_bits:
|
||
+ * reads the specified bits from the file.
|
||
+ *
|
||
+ * pic_write_bits:
|
||
+ * writes the specified bits to the file.
|
||
+ */
|
||
+static data32 pic_read_bits(pi, bits)
|
||
+ struct pic_info *pi;
|
||
+ int bits;
|
||
+{
|
||
+ data32 r = 0;
|
||
+
|
||
+ while(bits > 0){
|
||
+ while(pi->bs.rest > 0 && bits > 0){
|
||
+ r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0);
|
||
+ pi->bs.cur <<= 1;
|
||
+ pi->bs.rest--;
|
||
+ bits--;
|
||
+ }
|
||
+ if(bits > 0){
|
||
+ int c;
|
||
+ if((c = fgetc(pi->fp)) == EOF){
|
||
+ pic_file_warning(pi, PIC_CORRUPT);
|
||
+ c = 0;
|
||
+ }
|
||
+ pi->bs.cur = c;
|
||
+ pi->bs.rest = 8;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return r;
|
||
+}
|
||
+
|
||
+static void pic_write_bits(pi, dat, bits)
|
||
+ struct pic_info *pi;
|
||
+ data32 dat;
|
||
+ int bits;
|
||
+{
|
||
+ data32 dat_mask = 1 << (bits - 1);
|
||
+ while(bits > 0){
|
||
+ while(pi->bs.rest < 8 && bits > 0){
|
||
+ pi->bs.cur <<= 1;
|
||
+ if(dat & dat_mask)
|
||
+ pi->bs.cur |= 1;
|
||
+ pi->bs.rest++;
|
||
+ bits--;
|
||
+ dat_mask >>= 1;
|
||
+ }
|
||
+ if(pi->bs.rest >= 8){
|
||
+ if(fputc((int)pi->bs.cur, pi->fp) == EOF)
|
||
+ pic_error(pi, PIC_WRITE);
|
||
+ pi->bs.cur = 0;
|
||
+ pi->bs.rest = 0;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ * This function extends sub-8-bit data to 8-bit data using bit-replication.
|
||
+ */
|
||
+static byte pic_pad_bit(bits, dat)
|
||
+ int bits;
|
||
+ data32 dat;
|
||
+{
|
||
+ switch(bits){
|
||
+ case 1:
|
||
+ if(dat & 1)
|
||
+ dat = 0xff;
|
||
+ else
|
||
+ dat = 0;
|
||
+ break;
|
||
+ case 2:
|
||
+ dat = dat << 6 | dat << 4 | dat << 2 | dat;
|
||
+ break;
|
||
+ case 3:
|
||
+ dat = dat << 5 | dat << 2 | dat >> 1;
|
||
+ break;
|
||
+ case 4:
|
||
+ dat = dat << 4 | dat;
|
||
+ break;
|
||
+ case 5:
|
||
+ dat = dat << 3 | dat >> 2;
|
||
+ break;
|
||
+ case 6:
|
||
+ dat = dat << 2 | dat >> 4;
|
||
+ break;
|
||
+ case 7:
|
||
+ dat = dat << 1 | dat >> 6;
|
||
+ }
|
||
+
|
||
+ return dat;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions initialize or clean up structures.
|
||
+ * pic_init_info:
|
||
+ * initializes a pic_info structure.
|
||
+ * pic_cleanup_pic_info:
|
||
+ * cleans up a pic_info structure.
|
||
+ * pic_cleanup_pinfo:
|
||
+ * cleans up a PICINFO structure.
|
||
+ */
|
||
+static void pic_init_info(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ pi->fp = NULL;
|
||
+ pi->bs.rest = 0;
|
||
+ pi->bs.cur = '\0';
|
||
+ pi->type = pi->mode = 0;
|
||
+ pi->width = pi->height = 0;
|
||
+ pi->aspect = 1.0;
|
||
+ pi->cbits = 0;
|
||
+ pi->cmapped = pi->cached = 0;
|
||
+ pi->cache.node = NULL;
|
||
+ pi->cmap = NULL;
|
||
+ pi->g_bits = pi->r_bits = pi->b_bits = pi->i_bits = 0;
|
||
+ pi->inv_gr = 0;
|
||
+ pi->tiled256 = 0;
|
||
+ pi->numcols = 0;
|
||
+ pi->writing_grey = 0;
|
||
+}
|
||
+
|
||
+static void pic_cleanup_pic_info(pi, writing)
|
||
+ struct pic_info *pi;
|
||
+ int writing;
|
||
+{
|
||
+ if(!writing && pi->fp)
|
||
+ fclose(pi->fp);
|
||
+ if(pi->cmap)
|
||
+ free(pi->cmap);
|
||
+ if(pi->cache.node)
|
||
+ free(pi->cache.node);
|
||
+ if(pi->data)
|
||
+ free(pi->data);
|
||
+ pi->fp = NULL;
|
||
+ pi->cmap = NULL;
|
||
+ pi->cache.node = NULL;
|
||
+ pi->data = NULL;
|
||
+}
|
||
+
|
||
+static void pic_cleanup_pinfo(pinfo)
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ if(pinfo->pic){
|
||
+ free(pinfo->pic);
|
||
+ pinfo->pic = NULL;
|
||
+ }
|
||
+ if(pinfo->comment){
|
||
+ free(pinfo->comment);
|
||
+ pinfo->comment = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Error Handlers.
|
||
+ * pic_memory_error:
|
||
+ * shows an error message and terminates.
|
||
+ * pic_error:
|
||
+ * shows a non-file error message and jumps to the entry for errors.
|
||
+ * pic_file_error:
|
||
+ * shows a file error message and jumps to the entry for errors.
|
||
+ * pic_file_warning:
|
||
+ * shows a file warning message.
|
||
+ */
|
||
+static void pic_memory_error(scm, fn)
|
||
+ char *scm, *fn;
|
||
+{
|
||
+ char buf[128];
|
||
+ sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn);
|
||
+ FatalError(buf);
|
||
+}
|
||
+
|
||
+static void pic_error(pi, mn)
|
||
+ struct pic_info *pi;
|
||
+ int mn;
|
||
+{
|
||
+ SetISTR(ISTR_WARNING, "%s", pic_msgs[mn]);
|
||
+ longjmp(pi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void pic_file_error(pi, mn)
|
||
+ struct pic_info *pi;
|
||
+ int mn;
|
||
+{
|
||
+ if(feof(pi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", pic_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", pic_msgs[mn], ERRSTR(errno));
|
||
+ longjmp(pi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void pic_file_warning(pi, mn)
|
||
+ struct pic_info *pi;
|
||
+ int mn;
|
||
+{
|
||
+ if(feof(pi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", pic_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", pic_msgs[mn], ERRSTR(errno));
|
||
+}
|
||
+
|
||
+static void pic_show_pic_info(pi)
|
||
+ struct pic_info *pi;
|
||
+{
|
||
+ fprintf(stderr, " file size: %ld.\n", pi->fsize);
|
||
+
|
||
+ fputs(" machine: ", stderr);
|
||
+ switch(pi->type){
|
||
+ case 0x0:
|
||
+ fputs("X68k", stderr);
|
||
+ break;
|
||
+ case 0x1:
|
||
+ fputs("PC-88VA", stderr);
|
||
+ if(pi->mode & 1)
|
||
+ fputs(",HR", stderr);
|
||
+ if(pi->mode & 2)
|
||
+ fputs(",tiled256", stderr);
|
||
+ break;
|
||
+ case 0x2:
|
||
+ fprintf(stderr,
|
||
+ "FM-TOWNS,%s-resolution", pi->mode == 5 ? "low" : "high");
|
||
+ break;
|
||
+ case 0x3:
|
||
+ fputs("Macintosh", stderr);
|
||
+ break;
|
||
+ case 0xf:
|
||
+ fputs("misc", stderr);
|
||
+ }
|
||
+ fputs("\n", stderr);
|
||
+
|
||
+ fprintf(stderr, " image size: %dx%d\n", pi->width, pi->height);
|
||
+ fprintf(stderr, " aspect: %f\n", pi->aspect);
|
||
+ fprintf(stderr, " cache: %s\n", pi->cached ? "on" : "off");
|
||
+ fprintf(stderr, " colormap: %s\n", pi->cmapped ? "on" : "off");
|
||
+ fprintf(stderr, " number of color bits: %d\n", pi->cbits);
|
||
+ fprintf(stderr, " number of RGB bits: R%d,G%d,B%d,I%d\n",
|
||
+ pi->r_bits, pi->g_bits, pi->b_bits, pi->i_bits);
|
||
+ fprintf(stderr, " inverted G&R: %s\n", pi->inv_gr ? "true" : "false");
|
||
+ fprintf(stderr, " number of colors: %d\n", pi->numcols);
|
||
+}
|
||
+
|
||
+/* Memory related routines. */
|
||
+static void *pic_malloc(n, fn)
|
||
+ size_t n;
|
||
+ char *fn;
|
||
+{
|
||
+ void *r = (void *) malloc(n);
|
||
+ if(r == NULL)
|
||
+ pic_memory_error("malloc", fn);
|
||
+ return r;
|
||
+}
|
||
+
|
||
+static void *pic_realloc(p, n, fn)
|
||
+ void *p;
|
||
+ size_t n;
|
||
+ char *fn;
|
||
+{
|
||
+ void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n);
|
||
+ if(r == NULL)
|
||
+ pic_memory_error("realloc", fn);
|
||
+ return r;
|
||
+}
|
||
+#endif /* HAVE_PIC */
|
||
diff -u -r --new-file xv-3.10a.orig/xvpic2.c xv-3.10a/xvpic2.c
|
||
--- xv-3.10a.orig/xvpic2.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvpic2.c 2007-04-15 17:02:32.000000000 -0500
|
||
@@ -0,0 +1,3608 @@
|
||
+/*
|
||
+ * $Id: xvpic2.c,v 2.9.1.14 1995/04/24 15:34:15 ikeyan Exp $
|
||
+ * xvpic2.c - load and save routines for `PIC2' format pictures.
|
||
+ *
|
||
+ *
|
||
+ * Outline
|
||
+ * =======
|
||
+ * xvpic2.c supports the PIC2 format image file. It is used some
|
||
+ * Japanese personal computer users.
|
||
+ *
|
||
+ * The PIC2 format is designed by A.Yanagisawa. It is an excellent
|
||
+ * format except for its encode/decode speed. ;-)
|
||
+ *
|
||
+ * The features of the PIC2 format:
|
||
+ * - Powerful header information (included author, filename, title,
|
||
+ * saver, product number, created date and comment).
|
||
+ * - Reversible compression, and very high compression ratio (in many
|
||
+ * cases, a higher compression ratio than the JPEG compression;
|
||
+ * because of its compression method, PIC2 is especially good at
|
||
+ * pictures like cell animation).
|
||
+ * - Can handle full-color (24 bits) image.
|
||
+ * - Can include multi image blocks into one PIC2 file.
|
||
+ * - Have four different block format (P2SS, P2SF, P2BM and
|
||
+ * P2BI). P2SS format uses arithmetic compression for storing
|
||
+ * data. P2SF uses normal run-length compression. P2BM and P2BI is
|
||
+ * raw image format. Select any one according to the situation.
|
||
+ *
|
||
+ * Explanation of the PIC2 compression:
|
||
+
|
||
+ * - In the first place, try to record pixel color, uses color caches
|
||
+ * which keep some recent colors, and formed according to color's
|
||
+ * frequency. PIC2 has some color cache spaces that are switched by
|
||
+ * upper pixel value of current pixel. If cache is hit, record
|
||
+ * that.
|
||
+ * - Unfortunately, in the case of color cache didn't hit, record the
|
||
+ * difference from the value estimated with the value of upper and
|
||
+ * left pixel of current pixel (similar to PNG's AVG predictor).
|
||
+ * - And extract image's color chain if exist, and record that (it
|
||
+ * results in image's outline).
|
||
+ * - In all cases, arithmetic compression is used in the final stage
|
||
+ * before writing the file, which in theory produces the ideal
|
||
+ * compression ratio (P2SS).
|
||
+ *
|
||
+ * Features
|
||
+ * ========
|
||
+ * - Support 3,6,9,12,15,18,21,24bit PIC2 format (Load/Save).
|
||
+ * - Support all image block formats of PIC2 (Load/Save).
|
||
+ * - Support multi block PIC2 file (Load/Save).
|
||
+ *
|
||
+ *
|
||
+ * Bugs
|
||
+ * ====
|
||
+ * - Unsupport 8bit PIC2 image file.
|
||
+ *
|
||
+ * If you find other bugs (surely exist :-)), send me bug-report.
|
||
+ *
|
||
+ *
|
||
+ * Author
|
||
+ * ======
|
||
+ * IKEMOTO Masahiro <ikeyan@airlab.cs.ritsumei.ac.jp>
|
||
+ */
|
||
+
|
||
+#define PIC2_IGNORE_UNUSED_FUNCTIONS
|
||
+#define NEEDSDIR
|
||
+
|
||
+#include "xv.h"
|
||
+#include <setjmp.h>
|
||
+
|
||
+#ifdef HAVE_PIC2
|
||
+
|
||
+typedef unsigned long pixel;
|
||
+
|
||
+#define pic2_cextoshort(addr) ( \
|
||
+ (((short) (((byte *) addr)[0])) << 8) | \
|
||
+ ( (short) (((byte *) addr)[1])) \
|
||
+)
|
||
+#define pic2_cextolong(addr) ( \
|
||
+ (((long) (((byte *) addr)[0])) << 24) | \
|
||
+ (((long) (((byte *) addr)[1])) << 16) | \
|
||
+ (((long) (((byte *) addr)[2])) << 8) | \
|
||
+ ( (long) (((byte *) addr)[3])) \
|
||
+)
|
||
+#define pic2_shorttocex(addr, n) { \
|
||
+ ((byte *) addr)[0] = (((unsigned short) (n) >> 8) & 0xff); \
|
||
+ ((byte *) addr)[1] = ( (unsigned short) (n) & 0xff); \
|
||
+}
|
||
+#define pic2_longtocex(addr, n) { \
|
||
+ ((byte *) addr)[0] = (((unsigned long) (n) >> 24) & 0xff); \
|
||
+ ((byte *) addr)[1] = (((unsigned long) (n) >> 16) & 0xff); \
|
||
+ ((byte *) addr)[2] = (((unsigned long) (n) >> 8) & 0xff); \
|
||
+ ((byte *) addr)[3] = ( (unsigned long) (n) & 0xff); \
|
||
+}
|
||
+#define pic2_shift_bits(b, n) (((n) > 0) ? ((b) << (n)) : ((b) >> -(n)))
|
||
+
|
||
+#define PIC2_READ_MODE 0
|
||
+#define PIC2_WRITE_MODE 1
|
||
+
|
||
+#define PIC2_ARITH_CACHE 32
|
||
+#define PIC2_ARITH_CONTEXT 128
|
||
+#define PIC2_FAST_CACHE 64
|
||
+
|
||
+#define PIC2_HEADER_SIZE 124
|
||
+#define PIC2_BLOCK_HEADER_SIZE 26
|
||
+
|
||
+struct pic2_header {
|
||
+ char magic[4];
|
||
+ char name[18];
|
||
+ char subtitle[8];
|
||
+ char crlf0[2];
|
||
+ char title[30];
|
||
+ char crlf1[2];
|
||
+ char saver[30];
|
||
+ char crlf2[2];
|
||
+ char eof[1];
|
||
+ char reserve0[1];
|
||
+ short flag;
|
||
+ short no;
|
||
+ long time;
|
||
+ long size;
|
||
+ short depth;
|
||
+ short x_aspect;
|
||
+ short y_aspect;
|
||
+ short x_max;
|
||
+ short y_max;
|
||
+ long reserve1;
|
||
+};
|
||
+
|
||
+struct pic2_block {
|
||
+ char id[4];
|
||
+ long size;
|
||
+ short flag;
|
||
+ short x_wid;
|
||
+ short y_wid;
|
||
+ short x_offset;
|
||
+ short y_offset;
|
||
+ long opaque;
|
||
+ long reserve;
|
||
+};
|
||
+
|
||
+struct pic2_info {
|
||
+ jmp_buf jmp;
|
||
+ FILE *fp;
|
||
+ struct {
|
||
+ int rest;
|
||
+ byte cur;
|
||
+ int bits;
|
||
+ char zero;
|
||
+ }bs;
|
||
+ long fsize;
|
||
+ struct pic2_header *header;
|
||
+ struct pic2_block *block;
|
||
+ int n_pal;
|
||
+ int pal_bits;
|
||
+ byte pal[256][3];
|
||
+ char *comment;
|
||
+ char mode;
|
||
+ long next_pos;
|
||
+ long block_pos;
|
||
+ short x_max;
|
||
+ short y_max;
|
||
+ int ynow;
|
||
+ byte *buf;
|
||
+ pixel *vram_prev;
|
||
+ pixel *vram_now;
|
||
+ pixel *vram_next;
|
||
+ short *flag_now;
|
||
+ short *flag_next;
|
||
+ short *flag2_now;
|
||
+ short *flag2_next;
|
||
+ short *flag2_next2;
|
||
+ pixel (*cache)[PIC2_ARITH_CACHE];
|
||
+ unsigned short *cache_pos;
|
||
+ unsigned short *mulu_tab;
|
||
+ long aa;
|
||
+ long cc;
|
||
+ long dd;
|
||
+ char cache_hit_c;
|
||
+ int (*next_line) PARM((struct pic2_info *, pixel **));
|
||
+ char writing_grey;
|
||
+ char pagebname[64];
|
||
+ int pnum;
|
||
+};
|
||
+
|
||
+static void pic2_open_file PARM((struct pic2_info*,char*));
|
||
+static void pic2_read_header PARM((struct pic2_info*));
|
||
+static void pic2_read_block_header1 PARM((struct pic2_info*));
|
||
+static void pic2_read_block_header2 PARM((struct pic2_info*));
|
||
+static short pic2_arith_decode_bit PARM((struct pic2_info*,int));
|
||
+static short pic2_arith_decode_nn PARM((struct pic2_info*,int));
|
||
+static void pic2_arith_expand_chain PARM((struct pic2_info*,int,int,pixel));
|
||
+static short pic2_arith_get_number PARM((struct pic2_info*,int,int));
|
||
+static pixel pic2_arith_read_color PARM((struct pic2_info*,int));
|
||
+static int pic2_arith_expand_line PARM((struct pic2_info*,pixel**));
|
||
+static int pic2_arith_loader_init PARM((struct pic2_info*));
|
||
+static int pic2_fast_read_length PARM((struct pic2_info*));
|
||
+static void pic2_fast_expand_chain PARM((struct pic2_info*,int,pixel));
|
||
+static pixel pic2_fast_read_color PARM((struct pic2_info*,pixel));
|
||
+static int pic2_fast_expand_line PARM((struct pic2_info*,pixel**));
|
||
+static int pic2_fast_loader_init PARM((struct pic2_info*));
|
||
+static int pic2_beta_expand_line PARM((struct pic2_info*,pixel**));
|
||
+static int pic2_beta_loader_init PARM((struct pic2_info*));
|
||
+static void pic2_make_xvpic PARM((struct pic2_info*,byte**,
|
||
+ byte*,byte*,byte*));
|
||
+static void pic2_make_pagefile PARM((struct pic2_info*,char*,int));
|
||
+static void pic2_setup_pic2_info PARM((struct pic2_info*,
|
||
+ char*,char*,char*,char*,
|
||
+ int,int,int,int,int,int,char *));
|
||
+static void pic2_append PARM((struct pic2_info*));
|
||
+static void pic2_write_header1 PARM((struct pic2_info*));
|
||
+static void pic2_write_header2 PARM((struct pic2_info*));
|
||
+static void pic2_write_block_header PARM((struct pic2_info*));
|
||
+static void pic2_arith_write_zero_bit PARM((struct pic2_info*));
|
||
+static void pic2_arith_flush_bit_buf PARM((struct pic2_info*));
|
||
+static void pic2_arith_carry_bit PARM((struct pic2_info*));
|
||
+static void pic2_arith_encode_bit PARM((struct pic2_info*,int,int));
|
||
+static void pic2_arith_encode_nbyte PARM((struct pic2_info*,int,int,int));
|
||
+static void pic2_arith_encode_nn PARM((struct pic2_info*,int,int));
|
||
+static void pic2_arith_press_chain PARM((struct pic2_info*,int));
|
||
+static void pic2_arith_put_number PARM((struct pic2_info*,int,int,int));
|
||
+static void pic2_arith_write_color PARM((struct pic2_info*,int));
|
||
+static void pic2_arith_press_line2 PARM((struct pic2_info*));
|
||
+static int pic2_arith_press_line PARM((struct pic2_info*,pixel**));
|
||
+static int pic2_arith_saver_init PARM((struct pic2_info*,pixel**));
|
||
+static void pic2_fast_write_length PARM((struct pic2_info*,int));
|
||
+static void pic2_fast_press_chain PARM((struct pic2_info*,int));
|
||
+static void pic2_fast_press_chain2 PARM((struct pic2_info*,int));
|
||
+static void pic2_fast_flush_chain PARM((struct pic2_info*));
|
||
+static void pic2_fast_write_color PARM((struct pic2_info*,int));
|
||
+static void pic2_fast_press_line2 PARM((struct pic2_info*));
|
||
+static int pic2_fast_press_line PARM((struct pic2_info*,pixel**));
|
||
+static int pic2_fast_saver_init PARM((struct pic2_info*,pixel**));
|
||
+static int pic2_beta_press_line PARM((struct pic2_info*,pixel**));
|
||
+static int pic2_beta_saver_init PARM((struct pic2_info*,pixel**));
|
||
+static void pic2_write_data PARM((struct pic2_info*,byte*,
|
||
+ int,int,int,int,int,
|
||
+ byte*,byte*,byte*,int,int));
|
||
+static int pic2_next_line PARM((struct pic2_info*,pixel**));
|
||
+static int pic2_next_block PARM((struct pic2_info*));
|
||
+static int pic2_find_block PARM((struct pic2_info*));
|
||
+static int pic2_load_block PARM((struct pic2_info*));
|
||
+static int pic2_save_block PARM((struct pic2_info*,pixel**,
|
||
+ int,int,int,int,char*,pixel));
|
||
+#ifndef PIC2_IGNORE_UNUSED_FUNCTIONS
|
||
+static void pic2_read_palette PARM((struct pic2_info*,
|
||
+ byte*,byte*,byte*));
|
||
+static void pic2_write_palette PARM((struct pic2_info*,int,int,
|
||
+ byte*,byte*,byte*));
|
||
+#endif /* !PIC2_IGNORE_UNUSED_FUNCTIONS */
|
||
+static byte pic2_convert_color_bits PARM((int,int,int));
|
||
+static byte pic2_pad_color_bits PARM((int,int,int));
|
||
+static byte pic2_reduce_color_bits PARM((int,int,int));
|
||
+static pixel pic2_exchange_rg PARM((pixel,int));
|
||
+static void pic2_handle_para PARM((struct pic2_info*,int));
|
||
+static int pic2_alloc_buffer PARM((struct pic2_info*));
|
||
+static void pic2_free_buffer PARM((struct pic2_info*));
|
||
+static long pic2_seek_file PARM((struct pic2_info*,long,int));
|
||
+static long pic2_tell_file PARM((struct pic2_info*));
|
||
+static int pic2_read_file PARM((struct pic2_info*,void*,size_t));
|
||
+static long pic2_read_long PARM((struct pic2_info*));
|
||
+static short pic2_read_short PARM((struct pic2_info*));
|
||
+static char pic2_read_char PARM((struct pic2_info*));
|
||
+static int pic2_write_file PARM((struct pic2_info*,void*,size_t));
|
||
+static int pic2_write_long PARM((struct pic2_info*,long));
|
||
+static int pic2_write_short PARM((struct pic2_info*,int));
|
||
+static int pic2_write_char PARM((struct pic2_info*,int));
|
||
+static unsigned long pic2_read_bits PARM((struct pic2_info*,int));
|
||
+static void pic2_write_bits PARM((struct pic2_info*,
|
||
+ unsigned long,int));
|
||
+static void pic2_flush_bits PARM((struct pic2_info*));
|
||
+static void pic2_memory_error PARM((char*,char*));
|
||
+static void pic2_error PARM((struct pic2_info*,int));
|
||
+static void pic2_file_error PARM((struct pic2_info*,int));
|
||
+static void pic2_init_info PARM((struct pic2_info*));
|
||
+static void pic2_cleanup_pic2_info PARM((struct pic2_info*,int));
|
||
+static void pic2_cleanup_pinfo PARM((PICINFO*));
|
||
+static void pic2_show_pic2_info PARM((struct pic2_info*));
|
||
+static char *pic2_strncpy PARM((char*,char*,size_t));
|
||
+static void *pic2_malloc PARM((size_t,char*));
|
||
+static void *pic2_new PARM((size_t,char*));
|
||
+
|
||
+static int WritePIC2 PARM((FILE*,byte*,int,int,int,
|
||
+ byte*,byte*,byte*,int,int,char*,
|
||
+ int,int,int,int,int,char*));
|
||
+
|
||
+static char *pic2_id = "P2DT";
|
||
+
|
||
+/* Error Messages */
|
||
+static char *pic2_msgs[] = {
|
||
+ NULL,
|
||
+#define PIC2_OPEN 1
|
||
+ "can't open file.",
|
||
+#define PIC2_CORRUPT 2
|
||
+ "file corrupted.",
|
||
+#define PIC2_FORMAT 3
|
||
+ "not PIC2 format.",
|
||
+#define PIC2_DEPTH 4
|
||
+ "bit depths not divisible by 3 are unsupported.",
|
||
+#define PIC2_TMPFILE 5
|
||
+ "unable to create temporary filename???",
|
||
+#define PIC2_PAGE 6
|
||
+ "couldn't load the page.",
|
||
+#define PIC2_APPEND 7
|
||
+ "cannot append.",
|
||
+#define PIC2_WRITE 8
|
||
+ "write failed.",
|
||
+};
|
||
+
|
||
+struct _form_tab {
|
||
+ char *id;
|
||
+ int (*loader_init) PARM((struct pic2_info *));
|
||
+ int (*saver_init) PARM((struct pic2_info *, pixel **));
|
||
+} form_tab[] = {
|
||
+ { "P2SS", pic2_arith_loader_init, pic2_arith_saver_init},
|
||
+ { "P2SF", pic2_fast_loader_init, pic2_fast_saver_init},
|
||
+ { "P2BM", pic2_beta_loader_init, pic2_beta_saver_init},
|
||
+ { "P2BI", pic2_beta_loader_init, pic2_beta_saver_init},
|
||
+};
|
||
+#define n_form_tab (sizeof(form_tab) / sizeof(struct _form_tab))
|
||
+#define P2SS 0
|
||
+#define P2SF 1
|
||
+#define P2BM 2
|
||
+#define P2BI 3
|
||
+
|
||
+/* The main routine to load a PIC2 file. */
|
||
+int LoadPIC2(fname, pinfo, quick)
|
||
+char *fname;
|
||
+PICINFO *pinfo;
|
||
+int quick;
|
||
+{
|
||
+ int e, i, block;
|
||
+ struct pic2_info pic2;
|
||
+
|
||
+ if (DEBUG)
|
||
+ fputs("LoadPIC2:\n", stderr);
|
||
+
|
||
+ pic2_init_info(&pic2);
|
||
+
|
||
+ if ((e = setjmp(pic2.jmp)) != 0){
|
||
+ /* When an error occurs, comes here. */
|
||
+ pic2_free_buffer(&pic2);
|
||
+ pic2_cleanup_pic2_info(&pic2, 0);
|
||
+ pic2_cleanup_pinfo(pinfo);
|
||
+ if (pic2split)
|
||
+ KillPageFiles(pic2.pagebname, pic2.pnum);
|
||
+ SetCursors(-1);
|
||
+ if (DEBUG)
|
||
+ fputs("\n", stderr);
|
||
+ return (0);
|
||
+ }
|
||
+ pic2_open_file(&pic2, fname);
|
||
+ pic2_read_header(&pic2);
|
||
+
|
||
+ if ((i = pic2_find_block(&pic2)) == 0)
|
||
+ pic2_file_error(&pic2, PIC2_CORRUPT);
|
||
+
|
||
+ block = 1;
|
||
+ while(i == 2) {
|
||
+ SetISTR(ISTR_WARNING, "unknown or invalid block #%d.", block);
|
||
+ i = pic2_next_block(&pic2);
|
||
+ block++;
|
||
+ }
|
||
+
|
||
+ if (pic2split && !quick) {
|
||
+ char firstpage[512];
|
||
+ struct stat st;
|
||
+#ifndef USE_MKSTEMP
|
||
+ int tmpfd;
|
||
+#endif
|
||
+
|
||
+#ifndef VMS
|
||
+ sprintf(pic2.pagebname, "%s/xvpic2XXXXXX", tmpdir);
|
||
+#else
|
||
+ sprintf(pic2.pagebname, "Sys$Scratch:xvpic2XXXXXX");
|
||
+#endif
|
||
+#ifdef USE_MKSTEMP
|
||
+ close(mkstemp(pic2.pagebname));
|
||
+#else
|
||
+ mktemp(pic2.pagebname);
|
||
+ tmpfd = open(pic2.pagebname, O_WRONLY|O_CREAT|O_EXCL, S_IRWUSR);
|
||
+ if (tmpfd < 0) FatalError("LoadPIC2(): can't create temporary file");
|
||
+ close(tmpfd);
|
||
+#endif
|
||
+ if (pic2.pagebname[0] == '\0')
|
||
+ pic2_error(&pic2, PIC2_TMPFILE);
|
||
+ strcat(pic2.pagebname, ".");
|
||
+
|
||
+ sprintf(firstpage, "%s%d", pic2.pagebname, 1);
|
||
+ if (stat(firstpage, &st)) {
|
||
+ for (pic2.pnum = 1; i >= 1; pic2.pnum++) {
|
||
+ pic2_load_block(&pic2);
|
||
+ pic2_make_pagefile(&pic2, pic2.pagebname, pic2.pnum);
|
||
+ while(block++, (i = pic2_next_block(&pic2)) == 2)
|
||
+ SetISTR(ISTR_WARNING,
|
||
+ "unknown or invalid block #%d.", block);
|
||
+ }
|
||
+ pinfo->numpages = --pic2.pnum;
|
||
+ if (!LoadPIC2(firstpage, pinfo, 1))
|
||
+ pic2_error(&pic2, PIC2_PAGE);
|
||
+ if (pic2.pnum == 1)
|
||
+ unlink(firstpage);
|
||
+ else
|
||
+ strcpy(pinfo->pagebname, pic2.pagebname);
|
||
+ } else
|
||
+ if (!LoadPIC2(fname, pinfo, 1))
|
||
+ pic2_error(&pic2, PIC2_PAGE);
|
||
+ } else {
|
||
+ char buf[128], format[64];
|
||
+ int j;
|
||
+
|
||
+ pinfo->w = pic2.x_max;
|
||
+ pinfo->h = pic2.y_max;
|
||
+ pinfo->normw = pinfo->w;
|
||
+ pinfo->normh = pinfo->h;
|
||
+ pinfo->type = PIC24;
|
||
+ for (j = 0; j < n_form_tab; j++) {
|
||
+ if (xvbcmp(pic2.block->id, form_tab[j].id, (size_t) 4) == 0)
|
||
+ break;
|
||
+ }
|
||
+ pinfo->frmType = F_PIC2;
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ pinfo->comment = pic2.comment;
|
||
+
|
||
+ if (pic2split) {
|
||
+ pic2_make_xvpic(&pic2, &pinfo->pic, pinfo->r, pinfo->g, pinfo->b);
|
||
+ strcpy(format, form_tab[j].id);
|
||
+ } else {
|
||
+ for (pic2.pnum = 1; i >= 1; pic2.pnum++) {
|
||
+ SetISTR(ISTR_INFO, "composing block #%d", block);
|
||
+ pic2_make_xvpic(&pic2, &pinfo->pic,
|
||
+ pinfo->r, pinfo->g, pinfo->b);
|
||
+ while(block++, (i = pic2_next_block(&pic2)) == 2)
|
||
+ SetISTR(ISTR_WARNING,
|
||
+ "unknown or invalid block #%d.", block);
|
||
+ }
|
||
+ if (--block > 1)
|
||
+ if (block != --pic2.pnum)
|
||
+ sprintf(format, "MultiBlock[%d/%d]", block, pic2.pnum);
|
||
+ else
|
||
+ sprintf(format, "MultiBlock[%d]", block);
|
||
+ else
|
||
+ strcpy(format, form_tab[j].id);
|
||
+ }
|
||
+ sprintf(buf, "PIC2(%s). %d colors (%ld bytes)", format,
|
||
+ (int) 1 << pic2.header->depth, pic2.fsize);
|
||
+ strcat(pinfo->fullInfo, buf);
|
||
+ sprintf(pinfo->shrtInfo, "%dx%d(aspect %4.2f) PIC2(%s).",
|
||
+ pinfo->w, pinfo->h,
|
||
+ (float) pic2.header->x_aspect / (float) pic2.header->y_aspect,
|
||
+ format);
|
||
+ if (!nopicadjust)
|
||
+ normaspect = (float) pic2.header->x_aspect
|
||
+ / (float) pic2.header->y_aspect;
|
||
+ }
|
||
+ pic2_cleanup_pic2_info(&pic2, 0);
|
||
+ SetCursors(-1);
|
||
+ if (DEBUG)
|
||
+ fputs("\n", stderr);
|
||
+ return (1);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function opens the file, and set its size.
|
||
+ */
|
||
+static void pic2_open_file(pi, fname)
|
||
+ struct pic2_info *pi;
|
||
+ char *fname;
|
||
+{
|
||
+ if ((pi->fp = fopen(fname, "rb")) == NULL)
|
||
+ pic2_file_error(pi, PIC2_OPEN);
|
||
+ fseek(pi->fp, (size_t) 0, SEEK_END);
|
||
+ pi->fsize = ftell(pi->fp);
|
||
+ fseek(pi->fp, (size_t) 0, SEEK_SET);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions read the PIC2 header informations.
|
||
+ * pic2_read_header:
|
||
+ * reads the PIC2 header.
|
||
+ * pic2_read_block_header1:
|
||
+ * reads the id number of block header and the size of block.
|
||
+ * pic2_read_block_header2:
|
||
+ * reads the rest of block header.
|
||
+ */
|
||
+static void pic2_read_header(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ long s_comment;
|
||
+
|
||
+ pi->mode = PIC2_READ_MODE;
|
||
+
|
||
+ /* read header image */
|
||
+ pic2_read_file(pi, pi->header->magic, 4);
|
||
+ pic2_read_file(pi, pi->header->name, 18);
|
||
+ pic2_read_file(pi, pi->header->subtitle, 8);
|
||
+ pic2_read_file(pi, pi->header->crlf0, 2);
|
||
+ pic2_read_file(pi, pi->header->title, 30);
|
||
+ pic2_read_file(pi, pi->header->crlf1, 2);
|
||
+ pic2_read_file(pi, pi->header->saver, 30);
|
||
+ pic2_read_file(pi, pi->header->crlf2, 2);
|
||
+ pic2_read_file(pi, pi->header->eof, 1);
|
||
+ pic2_read_file(pi, pi->header->reserve0, 1);
|
||
+ pi->header->flag = pic2_read_short(pi);
|
||
+ pi->header->no = pic2_read_short(pi);
|
||
+ pi->header->time = pic2_read_long(pi);
|
||
+ pi->header->size = pic2_read_long(pi);
|
||
+ pi->header->depth = pic2_read_short(pi);
|
||
+ pi->header->x_aspect = pic2_read_short(pi);
|
||
+ pi->header->y_aspect = pic2_read_short(pi);
|
||
+ pi->header->x_max = pic2_read_short(pi);
|
||
+ pi->header->y_max = pic2_read_short(pi);
|
||
+ pi->header->reserve1 = pic2_read_long(pi);
|
||
+
|
||
+ /* check magic number */
|
||
+ if (strncmp(pi->header->magic, pic2_id, (size_t) 4) != 0)
|
||
+ pic2_error(pi, PIC2_FORMAT);
|
||
+
|
||
+ /* read palette data, if exists */
|
||
+ if (pi->header->flag & 1) {
|
||
+ pi->pal_bits = pic2_read_char(pi);
|
||
+ pi->n_pal = pic2_read_short(pi);
|
||
+ pic2_read_file(pi, pi->pal, (size_t) (pi->n_pal * 3));
|
||
+ }
|
||
+
|
||
+ /* read comments */
|
||
+ s_comment = pi->header->size - pic2_tell_file(pi);
|
||
+ pi->comment = pic2_new(s_comment + 1, "pic2_read_header");
|
||
+ pic2_read_file(pi, pi->comment, (size_t) s_comment);
|
||
+ pi->comment[s_comment] = '\0';
|
||
+
|
||
+ pi->x_max = pi->header->x_max;
|
||
+ pi->y_max = pi->header->y_max;
|
||
+
|
||
+ /* set initial block point */
|
||
+ pi->next_pos = pic2_tell_file(pi);
|
||
+}
|
||
+
|
||
+static void pic2_read_block_header1(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ pic2_read_file(pi, pi->block->id, 4);
|
||
+ pi->block->size = pic2_read_long(pi);
|
||
+}
|
||
+
|
||
+static void pic2_read_block_header2(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ pi->block->flag = pic2_read_short(pi);
|
||
+ pi->block->x_wid = pic2_read_short(pi);
|
||
+ pi->block->y_wid = pic2_read_short(pi);
|
||
+ pi->block->x_offset = pic2_read_short(pi);
|
||
+ pi->block->y_offset = pic2_read_short(pi);
|
||
+ pi->block->opaque = pic2_read_long(pi);
|
||
+ pi->block->reserve = pic2_read_long(pi);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions are arithmetic pic2 format extractor.
|
||
+ */
|
||
+static short pic2_arith_decode_bit(pi, c)
|
||
+struct pic2_info *pi;
|
||
+int c;
|
||
+{
|
||
+ unsigned short pp;
|
||
+
|
||
+ pp = pi->mulu_tab[(pi->aa & 0x7f00) / 2 + c];
|
||
+ if (pi->dd >= (int) pp) {
|
||
+ pi->dd -= pp;
|
||
+ pi->aa -= pp;
|
||
+
|
||
+ while ((short) pi->aa >= 0) {
|
||
+ pi->dd *= 2;
|
||
+ if (pic2_read_bits(pi, 1))
|
||
+ pi->dd++;
|
||
+ pi->aa *= 2;
|
||
+ }
|
||
+ return (1);
|
||
+ } else {
|
||
+ pi->aa = pp;
|
||
+
|
||
+ while ((short) pi->aa >= 0) {
|
||
+ pi->dd *= 2;
|
||
+ if (pic2_read_bits(pi, 1))
|
||
+ pi->dd++;
|
||
+ pi->aa *= 2;
|
||
+ }
|
||
+ return (0);
|
||
+ }
|
||
+}
|
||
+
|
||
+static short pic2_arith_decode_nn(pi, c)
|
||
+struct pic2_info *pi;
|
||
+int c;
|
||
+{
|
||
+ int n;
|
||
+
|
||
+ if (pic2_arith_decode_bit(pi, c)) {
|
||
+ /* n < 1 */
|
||
+ n = 0;
|
||
+ } else if (pic2_arith_decode_bit(pi, c + 1)) {
|
||
+ /* n < 1 + 2 */
|
||
+ n = 1;
|
||
+ if (pic2_arith_decode_bit(pi, c + 8))
|
||
+ n += 1;
|
||
+ } else if (pic2_arith_decode_bit(pi, c + 2)) {
|
||
+ /* n < 1 + 2 + 4 */
|
||
+ n = 1 + 2;
|
||
+ if (pic2_arith_decode_bit(pi, c + 8))
|
||
+ n += 1;
|
||
+ if (pic2_arith_decode_bit(pi, c + 9))
|
||
+ n += 2;
|
||
+ } else if (pic2_arith_decode_bit(pi, c + 3)) {
|
||
+ /* n < 1 + 2 + 4 + 8 */
|
||
+ n = 1 + 2 + 4;
|
||
+ if (pic2_arith_decode_bit(pi, c + 8))
|
||
+ n += 1;
|
||
+ if (pic2_arith_decode_bit(pi, c + 9))
|
||
+ n += 2;
|
||
+ if (pic2_arith_decode_bit(pi, c + 10))
|
||
+ n += 4;
|
||
+ } else if (pic2_arith_decode_bit(pi, c + 4)) {
|
||
+ /* n < 1 + 2 + 4 + 8 + 16 */
|
||
+ n = 1 + 2 + 4 + 8;
|
||
+ if (pic2_arith_decode_bit(pi, c + 8))
|
||
+ n += 1;
|
||
+ if (pic2_arith_decode_bit(pi, c + 9))
|
||
+ n += 2;
|
||
+ if (pic2_arith_decode_bit(pi, c + 10))
|
||
+ n += 4;
|
||
+ if (pic2_arith_decode_bit(pi, c + 11))
|
||
+ n += 8;
|
||
+ } else if (pic2_arith_decode_bit(pi, c + 5)) {
|
||
+ /* n < 1 + 2 + 4 + 8 + 16 + 32 */
|
||
+ n = 1 + 2 + 4 + 8 + 16;
|
||
+ if (pic2_arith_decode_bit(pi, c + 8))
|
||
+ n += 1;
|
||
+ if (pic2_arith_decode_bit(pi, c + 9))
|
||
+ n += 2;
|
||
+ if (pic2_arith_decode_bit(pi, c + 10))
|
||
+ n += 4;
|
||
+ if (pic2_arith_decode_bit(pi, c + 11))
|
||
+ n += 8;
|
||
+ if (pic2_arith_decode_bit(pi, c + 12))
|
||
+ n += 16;
|
||
+
|
||
+ } else if (pic2_arith_decode_bit(pi, c + 6)) {
|
||
+ /* n < 1 + 2 + 4 + 8 + 16 + 32 + 64 */
|
||
+ n = 1 + 2 + 4 + 8 + 16 + 32;
|
||
+ if (pic2_arith_decode_bit(pi, c + 8))
|
||
+ n += 1;
|
||
+ if (pic2_arith_decode_bit(pi, c + 9))
|
||
+ n += 2;
|
||
+ if (pic2_arith_decode_bit(pi, c + 10))
|
||
+ n += 4;
|
||
+ if (pic2_arith_decode_bit(pi, c + 11))
|
||
+ n += 8;
|
||
+ if (pic2_arith_decode_bit(pi, c + 12))
|
||
+ n += 16;
|
||
+ if (pic2_arith_decode_bit(pi, c + 13))
|
||
+ n += 32;
|
||
+
|
||
+ } else if (pic2_arith_decode_bit(pi, c + 7)) {
|
||
+ /* n < 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 */
|
||
+ n = 1 + 2 + 4 + 8 + 16 + 32 + 64;
|
||
+ if (pic2_arith_decode_bit(pi, c + 8))
|
||
+ n += 1;
|
||
+ if (pic2_arith_decode_bit(pi, c + 9))
|
||
+ n += 2;
|
||
+ if (pic2_arith_decode_bit(pi, c + 10))
|
||
+ n += 4;
|
||
+ if (pic2_arith_decode_bit(pi, c + 11))
|
||
+ n += 8;
|
||
+ if (pic2_arith_decode_bit(pi, c + 12))
|
||
+ n += 16;
|
||
+ if (pic2_arith_decode_bit(pi, c + 13))
|
||
+ n += 32;
|
||
+ if (pic2_arith_decode_bit(pi, c + 14))
|
||
+ n += 64;
|
||
+
|
||
+ } else {
|
||
+ n = 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128;
|
||
+ }
|
||
+ return (n);
|
||
+}
|
||
+
|
||
+static void pic2_arith_expand_chain(pi, x, y, cc)
|
||
+struct pic2_info *pi;
|
||
+int x, y;
|
||
+pixel cc;
|
||
+{
|
||
+ static const unsigned short c_tab[] = {
|
||
+ 80 + 6 * 5, /* -5 */
|
||
+ 80 + 6 * 4,
|
||
+ 80 + 6 * 3,
|
||
+ 80 + 6 * 2,
|
||
+ 80 + 6 * 1,
|
||
+ 80 + 6 * 0, /* 0 */
|
||
+ 80 + 6 * 0, /* 1 */
|
||
+ };
|
||
+ unsigned short b;
|
||
+
|
||
+ b = c_tab[pi->flag_now[x] + 5];
|
||
+ if (!pic2_arith_decode_bit(pi, b++)) {
|
||
+ if (pic2_arith_decode_bit(pi, b++)) { /* down */
|
||
+ pi->vram_next[x ] = cc;
|
||
+ pi->flag_next[x ] = -1;
|
||
+ } else if (pic2_arith_decode_bit(pi, b++)) { /* left */
|
||
+ pi->vram_next[x - 1] = cc;
|
||
+ pi->flag_next[x - 1] = -2;
|
||
+ } else if (pic2_arith_decode_bit(pi, b++)) { /* right */
|
||
+ pi->vram_next[x + 1] = cc;
|
||
+ pi->flag_next[x + 1] = -3;
|
||
+ } else if (pic2_arith_decode_bit(pi, b++)) { /* left2 */
|
||
+ pi->vram_next[x - 2] = cc;
|
||
+ pi->flag_next[x - 2] = -4;
|
||
+ } else { /* right2 */
|
||
+ pi->vram_next[x + 2] = cc;
|
||
+ pi->flag_next[x + 2] = -5;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static short pic2_arith_get_number(pi, c, bef)
|
||
+struct pic2_info *pi;
|
||
+int c, bef;
|
||
+{
|
||
+ unsigned short n;
|
||
+ byte maxcol;
|
||
+
|
||
+ maxcol = 0xff >> (8 - pi->header->depth / 3);
|
||
+
|
||
+ n = pic2_arith_decode_nn(pi, c);
|
||
+ if (bef > ((int) maxcol >> 1)) {
|
||
+ if (n > ((int) maxcol - bef) * 2)
|
||
+ n = maxcol - n;
|
||
+ else if (n & 1)
|
||
+ n = n / 2 + bef + 1;
|
||
+ else
|
||
+ n = bef - n / 2;
|
||
+ } else {
|
||
+ if ((int) n > (bef * 2))
|
||
+ n = n;
|
||
+ else if (n & 1)
|
||
+ n = n / 2 + bef + 1;
|
||
+ else
|
||
+ n = bef - n / 2;
|
||
+ }
|
||
+ return (n);
|
||
+}
|
||
+
|
||
+static pixel pic2_arith_read_color(pi, x)
|
||
+struct pic2_info *pi;
|
||
+int x;
|
||
+{
|
||
+ pixel c1, c2, cc;
|
||
+ unsigned short i, j, k, m;
|
||
+ short r, g, b, r0, g0, b0;
|
||
+ short colbits;
|
||
+ pixel rmask, gmask, bmask;
|
||
+ byte maxcol;
|
||
+
|
||
+ colbits = pi->header->depth / 3;
|
||
+ rmask = (0xff >> (8 - colbits)) << (colbits * 2);
|
||
+ gmask = (0xff >> (8 - colbits)) << colbits;
|
||
+ bmask = (0xff >> (8 - colbits));
|
||
+ maxcol = (byte) bmask;
|
||
+
|
||
+ c1 = pi->vram_prev[x];
|
||
+ k = ((c1 >> ((colbits - 3) * 3)) & 0x1c0)
|
||
+ | ((c1 >> ((colbits - 3) * 2)) & 0x038)
|
||
+ | ((c1 >> (colbits - 3) ) & 0x007);
|
||
+ if (colbits == 5)
|
||
+ k = pic2_exchange_rg(k, 3);
|
||
+
|
||
+ if (pic2_arith_decode_bit(pi, pi->cache_hit_c)) { /* ouch */
|
||
+ pi->cache_hit_c = 16;
|
||
+
|
||
+ c2 = pi->vram_now[x - 1];
|
||
+ r = ((c1 & rmask) + (c2 & rmask)) >> (colbits * 2 + 1);
|
||
+ g = ((c1 & gmask) + (c2 & gmask)) >> (colbits + 1);
|
||
+ b = ((c1 & bmask) + (c2 & bmask)) >> ( 1);
|
||
+
|
||
+ g0 = pic2_arith_get_number(pi, 32, g);
|
||
+ r = r + g0 - g;
|
||
+ if (r > (short) maxcol)
|
||
+ r = maxcol;
|
||
+ else if (r < 0)
|
||
+ r = 0;
|
||
+
|
||
+ b = b + g0 - g;
|
||
+ if (b > (short) maxcol)
|
||
+ b = maxcol;
|
||
+ else if (b < 0)
|
||
+ b = 0;
|
||
+
|
||
+ r0 = pic2_arith_get_number(pi, 48, r);
|
||
+ b0 = pic2_arith_get_number(pi, 64, b);
|
||
+
|
||
+ pi->cache_pos[k] = j = (pi->cache_pos[k] - 1) & (PIC2_ARITH_CACHE - 1);
|
||
+ pi->cache[k][j] = cc = (r0 << (colbits * 2)) | (g0 << colbits) | b0;
|
||
+ } else {
|
||
+ pi->cache_hit_c = 15;
|
||
+
|
||
+ j = pic2_arith_decode_nn(pi, 17);
|
||
+ m = pi->cache_pos[k];
|
||
+ i = (m + j / 2) & (PIC2_ARITH_CACHE - 1);
|
||
+ j = (m + j) & (PIC2_ARITH_CACHE - 1);
|
||
+
|
||
+ cc = pi->cache[k][j];
|
||
+ pi->cache[k][j] = pi->cache[k][i];
|
||
+ pi->cache[k][i] = pi->cache[k][m];
|
||
+ pi->cache[k][m] = cc;
|
||
+ }
|
||
+ return (cc);
|
||
+}
|
||
+
|
||
+static int pic2_arith_expand_line(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ int ymax;
|
||
+ int x, xw;
|
||
+ pixel cc;
|
||
+
|
||
+ pic2_handle_para(pi, 0);
|
||
+
|
||
+ xw = pi->block->x_wid;
|
||
+ ymax = pi->block->y_wid - 1;
|
||
+
|
||
+ if (pi->ynow > ymax)
|
||
+ return (-2); /* end */
|
||
+
|
||
+ /* set right end of previous line before left end of current line. */
|
||
+ if (pi->ynow == 0) {
|
||
+ cc = 0;
|
||
+ } else
|
||
+ cc = pi->vram_prev[xw - 1];
|
||
+ pi->vram_now[-1] = cc;
|
||
+
|
||
+ /* clear flag for change point */
|
||
+ xvbzero((char *) pi->flag_next, xw * sizeof(pi->flag_next[0]));
|
||
+
|
||
+ /* clear flag for position probability space */
|
||
+ xvbzero((char *) pi->flag2_next2, xw * sizeof(pi->flag2_next2[0]));
|
||
+
|
||
+ for (x = 0; x < xw; x++) {
|
||
+ if (pi->flag_now[x] < 0) {
|
||
+ cc = pi->vram_now[x];
|
||
+ if (pi->ynow < ymax)
|
||
+ pic2_arith_expand_chain(pi, x, pi->ynow, cc);
|
||
+ } else if (pic2_arith_decode_bit(pi, pi->flag2_now[x])) {
|
||
+ /* ajust probability space around of change point */
|
||
+ pi->flag2_now [x + 1]++;
|
||
+ pi->flag2_now [x + 2]++;
|
||
+ pi->flag2_next [x - 1]++;
|
||
+ pi->flag2_next [x ]++;
|
||
+ pi->flag2_next [x + 1]++;
|
||
+ pi->flag2_next2[x - 1]++;
|
||
+ pi->flag2_next2[x ]++;
|
||
+ pi->flag2_next2[x + 1]++;
|
||
+
|
||
+ pi->vram_now[x] = cc = pic2_arith_read_color(pi, x);
|
||
+ if (pi->ynow < ymax)
|
||
+ pic2_arith_expand_chain(pi, x, pi->ynow, cc);
|
||
+ } else
|
||
+ pi->vram_now[x] = cc;
|
||
+ }
|
||
+ if (line != NULL)
|
||
+ *line = pi->vram_now;
|
||
+ pi->ynow++;
|
||
+
|
||
+ pic2_handle_para(pi, 1);
|
||
+
|
||
+ return (pi->ynow - 1);
|
||
+}
|
||
+
|
||
+static int pic2_arith_loader_init(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ unsigned short p2b[256];
|
||
+ int i, xw;
|
||
+
|
||
+ pi->ynow = 0;
|
||
+
|
||
+ /* check the color depth */
|
||
+ if (pi->header->depth % 3)
|
||
+ pic2_error(pi, PIC2_DEPTH);
|
||
+
|
||
+ /* set function for extract next line */
|
||
+ pi->next_line = pic2_arith_expand_line;
|
||
+
|
||
+ /* clear cache and flags */
|
||
+ xw = pi->block->x_wid;
|
||
+ xvbzero((char *) pi->cache, 8 * 8 * 8 * sizeof(pi->cache[0]));
|
||
+ xvbzero((char *) pi->cache_pos, 8 * 8 * 8 * sizeof(pi->cache_pos[0]));
|
||
+
|
||
+ xvbzero((char *) pi->flag_now, xw * sizeof(pi->flag_now[0]));
|
||
+ xvbzero((char *) pi->flag2_now, 8 + xw * sizeof(pi->flag2_now[0]));
|
||
+ xvbzero((char *) pi->flag2_next, 8 + xw * sizeof(pi->flag2_next[0]));
|
||
+
|
||
+ /* go to picture data field */
|
||
+ pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
|
||
+
|
||
+ /* clear bit field marker */
|
||
+ pi->bs.rest = 0;
|
||
+ pi->bs.cur = 0;
|
||
+
|
||
+ /* read probability table */
|
||
+ for (i = 0; i < PIC2_ARITH_CONTEXT; i++)
|
||
+ p2b[i] = pic2_read_short(pi);
|
||
+
|
||
+ /* make multiplication table */
|
||
+ for (i = 0; i < 16384; i++) {
|
||
+ pi->mulu_tab[i] = (long) (i / 128 + 128) * (int) p2b[i & 127] / 256;
|
||
+ if (pi->mulu_tab[i] == 0) pi->mulu_tab[i] = 1;
|
||
+ }
|
||
+ /* initialize some valuables */
|
||
+ pi->aa = 0xffff;
|
||
+ pi->dd = 0;
|
||
+ for (i = 0; i < 16; i++) {
|
||
+ pi->dd *= 2;
|
||
+ if (pic2_read_bits(pi, 1))
|
||
+ pi->dd |= 1;
|
||
+ }
|
||
+ pi->cache_hit_c = 16;
|
||
+
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions are fast pic2 compression extractor.
|
||
+ */
|
||
+static int pic2_fast_read_length(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int a;
|
||
+
|
||
+ a = 0;
|
||
+ while (pic2_read_bits(pi, 1)) {
|
||
+ a++;
|
||
+ }
|
||
+ if (a == 0)
|
||
+ return (0);
|
||
+ return (pic2_read_bits(pi, a) + (1 << a) - 1);
|
||
+}
|
||
+
|
||
+static void pic2_fast_expand_chain(pi, x, cc)
|
||
+struct pic2_info *pi;
|
||
+int x;
|
||
+pixel cc;
|
||
+{
|
||
+ if (pic2_read_bits(pi, 1) != 0) {
|
||
+ if (pic2_read_bits(pi, 1) != 0) { /* down */
|
||
+ pi->vram_next[x] = cc;
|
||
+ pi->flag_next[x] = -1;
|
||
+ } else if (pic2_read_bits(pi, 1) != 0) {
|
||
+ if (pic2_read_bits(pi, 1) == 0) { /* left2down */
|
||
+ pi->vram_next[x - 2] = cc;
|
||
+ pi->flag_next[x - 2] = -1;
|
||
+ } else { /* left1down */
|
||
+ pi->vram_next[x - 1] = cc;
|
||
+ pi->flag_next[x - 1] = -1;
|
||
+ }
|
||
+ } else {
|
||
+ if (pic2_read_bits(pi, 1) == 0) { /* right2down */
|
||
+ pi->vram_next[x + 2] = cc;
|
||
+ pi->flag_next[x + 2] = -1;
|
||
+ } else { /* left1down */
|
||
+ pi->vram_next[x + 1] = cc;
|
||
+ pi->flag_next[x + 1] = -1;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static pixel pic2_fast_read_color(pi, bc)
|
||
+struct pic2_info *pi;
|
||
+pixel bc;
|
||
+{
|
||
+ pixel cc;
|
||
+ unsigned short j, k, m;
|
||
+ short depth, colbits;
|
||
+ pixel (*cache)[PIC2_FAST_CACHE];
|
||
+
|
||
+ depth = pi->header->depth;
|
||
+ colbits = depth / 3;
|
||
+ cache = (pixel (*)[PIC2_FAST_CACHE]) pi->cache;
|
||
+
|
||
+ bc = pic2_exchange_rg(bc, colbits);
|
||
+ k = pic2_shift_bits(bc, 8 - depth);
|
||
+ if (pic2_read_bits(pi, 1) == 0) {
|
||
+ pi->cache_pos[k] = m = (pi->cache_pos[k] - 1) & (PIC2_FAST_CACHE - 1);
|
||
+ cc = pic2_read_bits(pi, depth);
|
||
+ cc = pic2_exchange_rg(cc, colbits);
|
||
+ cache[k][m] = cc;
|
||
+ } else {
|
||
+ j = pic2_read_bits(pi, 6); /* 6= log2(PIC2_FAST_CACHE) */
|
||
+ m = pi->cache_pos[k];
|
||
+ cc = cache[k][(m + j) & (PIC2_FAST_CACHE - 1)];
|
||
+ }
|
||
+ return (cc);
|
||
+}
|
||
+
|
||
+static int pic2_fast_expand_line(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ int ymax;
|
||
+ int x, xw;
|
||
+ pixel cc;
|
||
+
|
||
+ pic2_handle_para(pi, 0);
|
||
+
|
||
+ xw = pi->block->x_wid;
|
||
+ ymax = pi->block->y_wid - 1;
|
||
+
|
||
+ if (pi->ynow > ymax)
|
||
+ return (-2);
|
||
+
|
||
+ if (pi->ynow == 0) {
|
||
+ pi->dd = 0;
|
||
+ pi->aa = pic2_fast_read_length(pi);
|
||
+ if (pi->aa == 1023)
|
||
+ pi->dd = 1023;
|
||
+ else if (pi->aa > 1023)
|
||
+ pi->aa--;
|
||
+ cc = 0;
|
||
+ } else
|
||
+ cc = pi->vram_prev[xw - 1];
|
||
+
|
||
+ xvbzero((char *) pi->flag_next, xw * sizeof(pi->flag_next[0]));
|
||
+
|
||
+ for (x = 0; x < xw; x++) {
|
||
+ if (pi->dd > 0) {
|
||
+ if (pi->flag_now[x] < 0) { /* on chain ? */
|
||
+ cc = pi->vram_now[x];
|
||
+ pic2_fast_expand_chain(pi, x, cc);
|
||
+ if (--pi->dd == 0) {
|
||
+ pi->aa = pic2_fast_read_length(pi);
|
||
+ if (pi->aa == 1023)
|
||
+ pi->dd = 1023;
|
||
+ else if (pi->aa > 1023)
|
||
+ pi->aa--;
|
||
+ }
|
||
+ } else
|
||
+ pi->vram_now[x] = cc;
|
||
+ } else {
|
||
+ if (pi->flag_now[x] < 0) { /* on chain ? */
|
||
+ cc = pi->vram_now[x];
|
||
+ pic2_fast_expand_chain(pi, x, cc);
|
||
+ } else if (--pi->aa < 0) {
|
||
+ cc = pi->vram_now[x] = pic2_fast_read_color(pi, cc);
|
||
+ pic2_fast_expand_chain(pi, x, cc);
|
||
+ pi->aa = pic2_fast_read_length(pi);
|
||
+ if (pi->aa == 1023)
|
||
+ pi->dd = 1023;
|
||
+ else if (pi->aa > 1023)
|
||
+ pi->aa--;
|
||
+ } else
|
||
+ pi->vram_now[x] = cc;
|
||
+ }
|
||
+ }
|
||
+ if (line != NULL)
|
||
+ *line = pi->vram_now;
|
||
+ pi->ynow++;
|
||
+
|
||
+ pic2_handle_para(pi, 1);
|
||
+
|
||
+ return (pi->ynow - 1);
|
||
+}
|
||
+
|
||
+static int pic2_fast_loader_init(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int xw;
|
||
+
|
||
+ pi->ynow = 0;
|
||
+
|
||
+ /* check the color depth */
|
||
+ if (pi->header->depth % 3)
|
||
+ pic2_error(pi, PIC2_DEPTH);
|
||
+
|
||
+ /* set function for extract next line */
|
||
+ pi->next_line = pic2_fast_expand_line;
|
||
+
|
||
+ /* clear cache and flags */
|
||
+ xw = pi->block->x_wid;
|
||
+ xvbzero((char *) pi->cache, sizeof(pi->cache[0]) * 256);
|
||
+ xvbzero((char *) pi->cache_pos, sizeof(pi->cache_pos[0]) * 8 * 8 * 8);
|
||
+ xvbzero((char *) pi->flag_now, (xw + 8) * sizeof(pi->flag_now[0]));
|
||
+ xvbzero((char *) pi->flag_next, (xw + 8) * sizeof(pi->flag_next[0]));
|
||
+
|
||
+ /* go to picture data field */
|
||
+ pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
|
||
+
|
||
+ /* clear bit field marker */
|
||
+ pi->bs.rest = 0;
|
||
+ pi->bs.cur = 0;
|
||
+
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions are beta pic2 format extractor.
|
||
+ */
|
||
+static int pic2_beta_expand_line(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ int i, xw, ymax;
|
||
+ byte a, b, c, *p;
|
||
+ pixel *pc;
|
||
+ short depth, pixbyte, colbits;
|
||
+
|
||
+ depth = pi->header->depth;
|
||
+ pixbyte = depth / 8 + ((depth % 8) > 0);
|
||
+ colbits = depth / 3;
|
||
+
|
||
+ xw = pi->block->x_wid;
|
||
+ ymax = pi->block->y_wid - 1;
|
||
+
|
||
+ if (pi->ynow > ymax)
|
||
+ return (-2); /* end */
|
||
+
|
||
+ pc = pi->vram_now;
|
||
+ p = (byte *) pi->vram_prev;
|
||
+ if (pixbyte == 3) {
|
||
+ pic2_read_file(pi, pi->vram_prev, (size_t) (xw * pixbyte));
|
||
+ for (i = 0; i < xw; i++, pc++) {
|
||
+ a = *p++;
|
||
+ b = *p++;
|
||
+ c = *p++;
|
||
+ *pc = ((pixel) a << 16) | ((pixel) b << 8) | (pixel) c;
|
||
+ }
|
||
+ } else if (pixbyte == 2) {
|
||
+ pic2_read_file(pi, pi->vram_prev, (size_t) (xw * 2));
|
||
+ if (strncmp(pi->block->id, "P2BM", 4) == 0) {
|
||
+ for (i = 0; i < xw; i++, pc++) {
|
||
+ a = *p++;
|
||
+ b = *p++;
|
||
+ *pc = ((pixel) a << 8) | (pixel) b;
|
||
+ if (colbits == 5) {
|
||
+ *pc >>= 1;
|
||
+ *pc = pic2_exchange_rg(*pc, colbits);
|
||
+ }
|
||
+ }
|
||
+ } else {
|
||
+ for (i = 0; i < xw; i++, pc++) {
|
||
+ a = *p++;
|
||
+ b = *p++;
|
||
+ *pc = ((pixel) b << 8) | (pixel) a;
|
||
+ if (colbits == 5) {
|
||
+ *pc >>= 1;
|
||
+ *pc = pic2_exchange_rg(*pc, colbits);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ } else {
|
||
+ pic2_read_file(pi, pi->vram_prev, (size_t) xw);
|
||
+ for (i = 0; i < xw; i++)
|
||
+ *pc++ = *p++;
|
||
+ }
|
||
+ if (line != NULL)
|
||
+ *line = pi->vram_now;
|
||
+
|
||
+ pc = pi->vram_prev;
|
||
+ pi->vram_prev = pi->vram_now;
|
||
+ pi->vram_now = pi->vram_next;
|
||
+ pi->vram_next = pc;
|
||
+
|
||
+ pi->ynow++;
|
||
+ return (pi->ynow - 1);
|
||
+}
|
||
+
|
||
+static int pic2_beta_loader_init(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ pi->ynow = 0;
|
||
+ pi->next_line = pic2_beta_expand_line;
|
||
+ pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Make a picture from the expanded data.
|
||
+ */
|
||
+static void pic2_make_xvpic(pi, xp, rp, gp, bp)
|
||
+struct pic2_info *pi;
|
||
+byte **xp, *rp, *gp, *bp;
|
||
+{
|
||
+ int line, i;
|
||
+ pixel *linep, opaque;
|
||
+ short colbits;
|
||
+ byte colmask;
|
||
+
|
||
+ if (*xp == NULL)
|
||
+ *xp = pic2_new((size_t) pi->x_max * pi->y_max * 3, "pic2_make_xvpic"); // GRR POSSIBLE OVERFLOW / FIXME
|
||
+
|
||
+ if (pi->block->flag & 1)
|
||
+ opaque = pi->block->opaque;
|
||
+ else
|
||
+ opaque = 0xffffffff;
|
||
+
|
||
+ colbits = pi->header->depth / 3;
|
||
+ colmask = 0xff >> (8 - colbits);
|
||
+
|
||
+ line = pic2_load_block(pi);
|
||
+ for (;;) {
|
||
+ int pic_idx;
|
||
+
|
||
+ line = pic2_next_line(pi, &linep);
|
||
+ if (line < 0)
|
||
+ break;
|
||
+ pic_idx = ((line + pi->block->y_offset) * pi->x_max
|
||
+ + pi->block->x_offset) * 3;
|
||
+
|
||
+ for (i = 0; i < pi->block->x_wid; i++, linep++) {
|
||
+ byte r, g, b;
|
||
+
|
||
+ if (*linep != opaque) {
|
||
+ r = ((*linep >> (colbits * 2)) & colmask);
|
||
+ r = pic2_convert_color_bits(r, colbits, 8);
|
||
+ g = ((*linep >> colbits ) & colmask);
|
||
+ g = pic2_convert_color_bits(g, colbits, 8);
|
||
+ b = ( *linep & colmask);
|
||
+ b = pic2_convert_color_bits(b, colbits, 8);
|
||
+ (*xp)[pic_idx++] = r;
|
||
+ (*xp)[pic_idx++] = g;
|
||
+ (*xp)[pic_idx++] = b;
|
||
+ } else
|
||
+ pic_idx += 3;
|
||
+
|
||
+ WaitCursor();
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function splits a multiblock PIC2 file into several pages.
|
||
+ */
|
||
+static void pic2_make_pagefile(pi, pagebname, pnum)
|
||
+struct pic2_info *pi;
|
||
+char *pagebname;
|
||
+int pnum;
|
||
+{
|
||
+ struct pic2_info pic2;
|
||
+ FILE *fp;
|
||
+ char pagefile[64], *buf;
|
||
+ size_t imagesize;
|
||
+
|
||
+ sprintf(pagefile, "%s%d", pagebname, pnum);
|
||
+ if ((fp = fopen(pagefile, "wb")) == NULL)
|
||
+ pic2_error(pi, PIC2_WRITE);
|
||
+
|
||
+ xvbcopy((char *) pi, (char *) &pic2, sizeof(struct pic2_info));
|
||
+ pic2.fp = fp;
|
||
+
|
||
+ pic2_write_header1(&pic2);
|
||
+
|
||
+ pic2_write_block_header(&pic2);
|
||
+
|
||
+ imagesize = pi->block->size - PIC2_BLOCK_HEADER_SIZE;
|
||
+ buf = (char *) pic2_malloc(imagesize, "pic2_make_pagefile");
|
||
+
|
||
+ pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
|
||
+ if (fread(buf, (size_t) 1, imagesize, pi->fp) < imagesize) {
|
||
+ free(buf);
|
||
+ pic2_file_error(pi, PIC2_CORRUPT);
|
||
+ }
|
||
+ if (fwrite(buf, (size_t) 1, imagesize, fp) < imagesize) {
|
||
+ free(buf);
|
||
+ pic2_error(pi, PIC2_WRITE);
|
||
+ }
|
||
+ free(buf);
|
||
+
|
||
+ pic2.next_pos = pic2_tell_file(&pic2);
|
||
+ pic2_write_header2(&pic2);
|
||
+
|
||
+ fclose(fp);
|
||
+}
|
||
+
|
||
+/* The main routine to save a PIC2 file. */
|
||
+static int WritePIC2(fp, pic0, ptype, w, h, rmap, gmap, bmap, numcols,
|
||
+ colorstyle, fname, type, depth, x_offset, y_offset,
|
||
+ append, comment)
|
||
+FILE *fp;
|
||
+byte *pic0;
|
||
+int ptype, w, h;
|
||
+byte *rmap, *gmap, *bmap;
|
||
+int numcols, colorstyle;
|
||
+char *fname;
|
||
+int type, depth;
|
||
+int x_offset, y_offset;
|
||
+int append;
|
||
+char *comment;
|
||
+{
|
||
+ struct pic2_info pic2;
|
||
+ char creator[256], title[256], saver[256];
|
||
+ int e;
|
||
+
|
||
+ if (DEBUG)
|
||
+ fputs("WritePIC2:\n", stderr);
|
||
+
|
||
+ pic2_init_info(&pic2);
|
||
+ pic2.fp = fp;
|
||
+ pic2.writing_grey = (colorstyle == F_GREYSCALE);
|
||
+
|
||
+ if ((e = setjmp(pic2.jmp)) != 0){
|
||
+ /* When an error occurs while writing, comes here. */
|
||
+ pic2_free_buffer(&pic2);
|
||
+ pic2_cleanup_pic2_info(&pic2, 1);
|
||
+ SetCursors(-1);
|
||
+ if (DEBUG)
|
||
+ fputs("\n", stderr);
|
||
+ return (-1);
|
||
+ }
|
||
+ sprintf(creator, "XV Version %s", VERSTR);
|
||
+ pic2_strncpy(title, comment, 30);
|
||
+ sprintf(saver, "XV %s/UNIX/Bradley", VERSTR);
|
||
+
|
||
+ if (!append) {
|
||
+ pic2_setup_pic2_info(&pic2, creator, fname, title, saver,
|
||
+ 0, depth, 1, 1, w, h, comment);
|
||
+ pic2_write_header1(&pic2);
|
||
+ } else {
|
||
+ pic2_read_header(&pic2);
|
||
+ pic2_append(&pic2);
|
||
+ free(pic2.comment);
|
||
+ pic2_setup_pic2_info(&pic2, creator, fname, title, saver,
|
||
+ 0, depth, 1, 1, w, h, comment);
|
||
+ }
|
||
+
|
||
+ pic2_write_data(&pic2, pic0, ptype, x_offset, y_offset, w, h,
|
||
+ rmap, gmap, bmap, type, depth);
|
||
+ pic2_write_header2(&pic2);
|
||
+
|
||
+ pic2_cleanup_pic2_info(&pic2, 1);
|
||
+ SetCursors(-1);
|
||
+ if (DEBUG)
|
||
+ fputs("\n", stderr);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function initializes pic2_info.
|
||
+ */
|
||
+static void pic2_setup_pic2_info(pi, name, fname, title, saver, no, depth,
|
||
+ x_aspect, y_aspect, x_max, y_max, comment)
|
||
+struct pic2_info *pi;
|
||
+char *name, *fname, *title, *saver;
|
||
+int no, depth;
|
||
+int x_aspect, y_aspect;
|
||
+int x_max, y_max;
|
||
+char *comment;
|
||
+{
|
||
+ char basename[256], *suffix;
|
||
+
|
||
+ pi->mode = PIC2_WRITE_MODE;
|
||
+
|
||
+ /* set magic number */
|
||
+ strncpy(pi->header->magic, pic2_id, 4);
|
||
+
|
||
+ /* set creator's name */
|
||
+ pic2_strncpy(pi->header->name, (char *) name, 18);
|
||
+
|
||
+ /* set title and subtitle */
|
||
+ pic2_strncpy(pi->header->title, (char *) title, 30);
|
||
+ strcpy(basename, BaseName(fname));
|
||
+ suffix = (char *) rindex(basename, '.');
|
||
+ if (suffix) {
|
||
+ suffix++;
|
||
+ if (!strcmp(suffix, "p2") || !strcmp(suffix, "P2"))
|
||
+ *(suffix - 1) = '\0';
|
||
+ }
|
||
+ pic2_strncpy(pi->header->subtitle, basename, 8);
|
||
+
|
||
+ /* set saver */
|
||
+ pic2_strncpy(pi->header->saver, saver, 30);
|
||
+
|
||
+ /* set picture number */
|
||
+ pi->header->no = no;
|
||
+
|
||
+ /* import comment */
|
||
+ pi->comment = comment;
|
||
+
|
||
+ /* set some picture's info */
|
||
+ pi->header->depth = depth;
|
||
+ pi->header->x_aspect = x_aspect;
|
||
+ pi->header->y_aspect = y_aspect;
|
||
+ pi->header->x_max = x_max;
|
||
+ pi->header->y_max = y_max;
|
||
+
|
||
+ /* set some gaps */
|
||
+ pi->header->crlf0[0] = pi->header->crlf1[0] = pi->header->crlf2[0] = 0x0d;
|
||
+ pi->header->crlf0[1] = pi->header->crlf1[1] = pi->header->crlf2[1] = 0x0a;
|
||
+
|
||
+ pi->header->eof[0] = 0x1a;
|
||
+ pi->header->reserve0[0] = 0;
|
||
+ pi->header->reserve1 = 0;
|
||
+
|
||
+ /* set palettes */
|
||
+ if (pi->n_pal > 0)
|
||
+ pi->header->flag = 1;
|
||
+ else
|
||
+ pi->header->flag = 0;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function appends to existing pic2 file.
|
||
+ */
|
||
+static void pic2_append(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int block;
|
||
+
|
||
+ block = pic2_find_block(pi);
|
||
+ while (block > 0)
|
||
+ block = pic2_next_block(pi);
|
||
+
|
||
+ if (block != 0)
|
||
+ pic2_error(pi, PIC2_APPEND);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions write the PIC2 header.
|
||
+ * pic2_write_header1:
|
||
+ * write palette data and comment.
|
||
+ * pic2_write_header2:
|
||
+ * write the terminate block and rest header.
|
||
+ * pic2_write_block_header:
|
||
+ * write the block header.
|
||
+ */
|
||
+static void pic2_write_header1(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ char *comment;
|
||
+
|
||
+ /* seek to block start position */
|
||
+ pic2_seek_file(pi, PIC2_HEADER_SIZE, SEEK_SET);
|
||
+
|
||
+ /* write palette */
|
||
+ if (pi->n_pal > 0) {
|
||
+ pic2_write_char(pi, pi->pal_bits);
|
||
+ pic2_write_short(pi, pi->n_pal);
|
||
+ pic2_write_file(pi, pi->pal, (size_t) (pi->n_pal * 3));
|
||
+ }
|
||
+ /* save comment */
|
||
+ comment = pi->comment;
|
||
+ if (pi->comment != NULL) {
|
||
+ for (comment = pi->comment; *comment; comment++) {
|
||
+ if (*comment == '\n') {
|
||
+ pic2_write_char(pi, '\r');
|
||
+ pic2_write_char(pi, '\n');
|
||
+ } else if (*comment != '\r')
|
||
+ pic2_write_char(pi, *comment);
|
||
+ }
|
||
+ pic2_write_char(pi, 0);
|
||
+ }
|
||
+ /* set the next block position */
|
||
+ pi->next_pos = pic2_tell_file(pi);
|
||
+ pi->header->size = pi->next_pos;
|
||
+}
|
||
+
|
||
+static void pic2_write_header2(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ pic2_seek_file(pi, pi->next_pos, SEEK_SET);
|
||
+
|
||
+ /* write terminate block */
|
||
+ pic2_write_long(pi, 0);
|
||
+ pic2_write_long(pi, 0);
|
||
+
|
||
+ /* set some header information */
|
||
+ if (pi->header->x_max < pi->x_max)
|
||
+ pi->header->x_max = pi->x_max;
|
||
+ if (pi->header->y_max < pi->x_max)
|
||
+ pi->header->y_max = pi->y_max;
|
||
+
|
||
+ pi->header->time = time(NULL);
|
||
+ pic2_seek_file(pi, 0, SEEK_SET);
|
||
+
|
||
+ /* write header image */
|
||
+ pic2_write_file(pi, pi->header->magic, 4);
|
||
+ pic2_write_file(pi, pi->header->name, 18);
|
||
+ pic2_write_file(pi, pi->header->subtitle, 8);
|
||
+ pic2_write_file(pi, pi->header->crlf0, 2);
|
||
+ pic2_write_file(pi, pi->header->title, 30);
|
||
+ pic2_write_file(pi, pi->header->crlf1, 2);
|
||
+ pic2_write_file(pi, pi->header->saver, 30);
|
||
+ pic2_write_file(pi, pi->header->crlf2, 2);
|
||
+ pic2_write_file(pi, pi->header->eof, 1);
|
||
+ pic2_write_file(pi, pi->header->reserve0, 1);
|
||
+ pic2_write_short(pi, pi->header->flag);
|
||
+ pic2_write_short(pi, pi->header->no);
|
||
+ pic2_write_long(pi, pi->header->time);
|
||
+ pic2_write_long(pi, pi->header->size);
|
||
+ pic2_write_short(pi, pi->header->depth);
|
||
+ pic2_write_short(pi, pi->header->x_aspect);
|
||
+ pic2_write_short(pi, pi->header->y_aspect);
|
||
+ pic2_write_short(pi, pi->header->x_max);
|
||
+ pic2_write_short(pi, pi->header->y_max);
|
||
+ pic2_write_long(pi, pi->header->reserve1);
|
||
+}
|
||
+
|
||
+static void pic2_write_block_header(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ pic2_write_file(pi, pi->block->id, 4);
|
||
+ pic2_write_long(pi, pi->block->size);
|
||
+ pic2_write_short(pi, pi->block->flag);
|
||
+ pic2_write_short(pi, pi->block->x_wid);
|
||
+ pic2_write_short(pi, pi->block->y_wid);
|
||
+ pic2_write_short(pi, pi->block->x_offset);
|
||
+ pic2_write_short(pi, pi->block->y_offset);
|
||
+ pic2_write_long(pi, pi->block->opaque);
|
||
+ pic2_write_long(pi, pi->block->reserve);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions implement the arithmetic-format compressor.
|
||
+ */
|
||
+#define pic2_arith_write_one_bit(pi) (pi->bs.bits++)
|
||
+
|
||
+static void pic2_arith_write_zero_bit(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ if (pi->bs.zero)
|
||
+ pic2_write_bits(pi, 0, 1);
|
||
+
|
||
+ while (pi->bs.bits--)
|
||
+ pic2_write_bits(pi, 1, 1);
|
||
+
|
||
+ pi->bs.bits = 0;
|
||
+ pi->bs.zero = 1;
|
||
+}
|
||
+
|
||
+static void pic2_arith_flush_bit_buf(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < 16; i++) {
|
||
+ if (pi->cc & 0x8000)
|
||
+ pic2_arith_write_one_bit(pi);
|
||
+ else
|
||
+ pic2_arith_write_zero_bit(pi);
|
||
+ pi->cc <<= 1;
|
||
+ }
|
||
+ pic2_arith_write_zero_bit(pi);
|
||
+ pic2_flush_bits(pi);
|
||
+}
|
||
+
|
||
+static void pic2_arith_carry_bit(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ pic2_write_bits(pi, 1, 1);
|
||
+
|
||
+ if (pi->bs.bits == 0) {
|
||
+ pi->bs.zero = 0;
|
||
+ } else {
|
||
+ while (--pi->bs.bits)
|
||
+ pic2_write_bits(pi, 0, 1);
|
||
+ pi->bs.zero = 1;
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic2_arith_encode_bit(pi, n, c)
|
||
+struct pic2_info *pi;
|
||
+int n, c;
|
||
+{
|
||
+ int pp;
|
||
+ long *c_sum, *c_0_sum;
|
||
+
|
||
+ c_sum = (long *) pi->mulu_tab;
|
||
+ c_0_sum = c_sum + PIC2_ARITH_CONTEXT + 1;
|
||
+
|
||
+ if (pi->dd == 0) {
|
||
+ c_sum[c]++;
|
||
+ if (n == 0)
|
||
+ c_0_sum[c]++;
|
||
+ return;
|
||
+ }
|
||
+ pp = pi->mulu_tab[(pi->aa & 0x7f00) / 2 + c];
|
||
+ if (n != 0) {
|
||
+ pi->cc = pi->cc + pp;
|
||
+ if (pi->cc > 0xffff) {
|
||
+ pic2_arith_carry_bit(pi);
|
||
+ pi->cc = pi->cc & 0xffff;
|
||
+ }
|
||
+ pi->aa = pi->aa - pp;
|
||
+ while (pi->aa < 0x8000) {
|
||
+ if (pi->cc & 0x8000)
|
||
+ pic2_arith_write_one_bit(pi);
|
||
+ else
|
||
+ pic2_arith_write_zero_bit(pi);
|
||
+ pi->cc = (pi->cc * 2) & 0xffff;
|
||
+ pi->aa = pi->aa * 2;
|
||
+ }
|
||
+ } else {
|
||
+ pi->aa = pp;
|
||
+
|
||
+ while (pi->aa < 0x8000) {
|
||
+ if (pi->cc & 0x8000)
|
||
+ pic2_arith_write_one_bit(pi);
|
||
+ else
|
||
+ pic2_arith_write_zero_bit(pi);
|
||
+ pi->cc = (pi->cc * 2) & 0xffff;
|
||
+ pi->aa = pi->aa * 2;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic2_arith_encode_nbyte(pi, n, c, max)
|
||
+struct pic2_info *pi;
|
||
+int n, c, max;
|
||
+{
|
||
+ short i;
|
||
+
|
||
+ for (i = 0; i < n; i++) {
|
||
+ pic2_arith_encode_bit(pi, 0, c + i);
|
||
+ }
|
||
+ if (n < max)
|
||
+ pic2_arith_encode_bit(pi, 1, c + n);
|
||
+}
|
||
+
|
||
+static void pic2_arith_encode_nn(pi, n, c)
|
||
+struct pic2_info *pi;
|
||
+int n, c;
|
||
+{
|
||
+ if (n < 1) {
|
||
+ pic2_arith_encode_bit(pi, 1, c);
|
||
+ } else if (n < 1 + 2) {
|
||
+ pic2_arith_encode_bit(pi, 0, c);
|
||
+ pic2_arith_encode_bit(pi, 1, c + 1);
|
||
+ n -= 1;
|
||
+ pic2_arith_encode_bit(pi, n & 1, c + 8);
|
||
+ } else if (n < 1 + 2 + 4) {
|
||
+ pic2_arith_encode_bit(pi, 0, c);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 1);
|
||
+ pic2_arith_encode_bit(pi, 1, c + 2);
|
||
+ n -= 1 + 2;
|
||
+ pic2_arith_encode_bit(pi, n & 1, c + 8);
|
||
+ pic2_arith_encode_bit(pi, n & 2, c + 9);
|
||
+ } else if (n < 1 + 2 + 4 + 8) {
|
||
+ pic2_arith_encode_bit(pi, 0, c);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 1);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 2);
|
||
+ pic2_arith_encode_bit(pi, 1, c + 3);
|
||
+ n -= 1 + 2 + 4;
|
||
+ pic2_arith_encode_bit(pi, n & 1, c + 8);
|
||
+ pic2_arith_encode_bit(pi, n & 2, c + 9);
|
||
+ pic2_arith_encode_bit(pi, n & 4, c + 10);
|
||
+ } else if (n < 1 + 2 + 4 + 8 + 16) {
|
||
+ pic2_arith_encode_bit(pi, 0, c);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 1);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 2);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 3);
|
||
+ pic2_arith_encode_bit(pi, 1, c + 4);
|
||
+ n -= 1 + 2 + 4 + 8;
|
||
+ pic2_arith_encode_bit(pi, n & 1, c + 8);
|
||
+ pic2_arith_encode_bit(pi, n & 2, c + 9);
|
||
+ pic2_arith_encode_bit(pi, n & 4, c + 10);
|
||
+ pic2_arith_encode_bit(pi, n & 8, c + 11);
|
||
+ } else if (n < 1 + 2 + 4 + 8 + 16 + 32) {
|
||
+ pic2_arith_encode_bit(pi, 0, c);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 1);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 2);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 3);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 4);
|
||
+ pic2_arith_encode_bit(pi, 1, c + 5);
|
||
+ n -= 1 + 2 + 4 + 8 + 16;
|
||
+ pic2_arith_encode_bit(pi, n & 1, c + 8);
|
||
+ pic2_arith_encode_bit(pi, n & 2, c + 9);
|
||
+ pic2_arith_encode_bit(pi, n & 4, c + 10);
|
||
+ pic2_arith_encode_bit(pi, n & 8, c + 11);
|
||
+ pic2_arith_encode_bit(pi, n & 16, c + 12);
|
||
+ } else if (n < 1 + 2 + 4 + 8 + 16 + 32 + 64) {
|
||
+ pic2_arith_encode_bit(pi, 0, c);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 1);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 2);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 3);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 4);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 5);
|
||
+ pic2_arith_encode_bit(pi, 1, c + 6);
|
||
+ n -= 1 + 2 + 4 + 8 + 16 + 32;
|
||
+ pic2_arith_encode_bit(pi, n & 1, c + 8);
|
||
+ pic2_arith_encode_bit(pi, n & 2, c + 9);
|
||
+ pic2_arith_encode_bit(pi, n & 4, c + 10);
|
||
+ pic2_arith_encode_bit(pi, n & 8, c + 11);
|
||
+ pic2_arith_encode_bit(pi, n & 16, c + 12);
|
||
+ pic2_arith_encode_bit(pi, n & 32, c + 13);
|
||
+ } else if (n < 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128) {
|
||
+ pic2_arith_encode_bit(pi, 0, c);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 1);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 2);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 3);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 4);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 5);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 6);
|
||
+ pic2_arith_encode_bit(pi, 1, c + 7);
|
||
+ n -= 1 + 2 + 4 + 8 + 16 + 32 + 64;
|
||
+ pic2_arith_encode_bit(pi, n & 1, c + 8);
|
||
+ pic2_arith_encode_bit(pi, n & 2, c + 9);
|
||
+ pic2_arith_encode_bit(pi, n & 4, c + 10);
|
||
+ pic2_arith_encode_bit(pi, n & 8, c + 11);
|
||
+ pic2_arith_encode_bit(pi, n & 16, c + 12);
|
||
+ pic2_arith_encode_bit(pi, n & 32, c + 13);
|
||
+ pic2_arith_encode_bit(pi, n & 64, c + 14);
|
||
+ } else {
|
||
+ pic2_arith_encode_bit(pi, 0, c);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 1);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 2);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 3);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 4);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 5);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 6);
|
||
+ pic2_arith_encode_bit(pi, 0, c + 7);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic2_arith_press_chain(pi, x)
|
||
+struct pic2_info *pi;
|
||
+int x;
|
||
+{
|
||
+ int b, d;
|
||
+ pixel c;
|
||
+
|
||
+ b = -(pi->flag_now[x]);
|
||
+ c = pi->vram_now[x];
|
||
+ d = 0;
|
||
+
|
||
+ if (b < 0)
|
||
+ b = 0;
|
||
+
|
||
+ if (pi->flag_next[x] == 1 && pi->vram_next[x] == c) {
|
||
+ d = 1;
|
||
+ pi->flag_next[x] = -1;
|
||
+ } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == c) {
|
||
+ d = 2;
|
||
+ pi->flag_next[x - 1] = -2;
|
||
+ } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == c) {
|
||
+ d = 3;
|
||
+ pi->flag_next[x + 1] = -3;
|
||
+ } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == c) {
|
||
+ d = 4;
|
||
+ pi->flag_next[x - 2] = -4;
|
||
+ } else if (pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == c) {
|
||
+ if ((pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == c)
|
||
+ || (pi->flag_now[x + 1] != 0 && pi->vram_now[x + 1] == c)
|
||
+ || (pi->flag_now[x + 3] != 0 && pi->vram_now[x + 3] == c)) {
|
||
+ pic2_arith_encode_nbyte(pi, 0, 80 + 6 * b, 5);
|
||
+ return;
|
||
+ }
|
||
+ d = 5;
|
||
+ pi->flag_next[x + 2] = -5;
|
||
+ }
|
||
+ pic2_arith_encode_nbyte(pi, d, 80 + 6 * b, 5);
|
||
+}
|
||
+
|
||
+static void pic2_arith_put_number(pi, xn, xa, xb)
|
||
+struct pic2_info *pi;
|
||
+int xn, xa, xb;
|
||
+{
|
||
+ short n;
|
||
+ byte maxcol;
|
||
+
|
||
+ maxcol = 0xff >> (8 - pi->header->depth / 3);
|
||
+
|
||
+ if (xa > ((int) maxcol >> 1)) {
|
||
+ if (xb > xa)
|
||
+ n = (xb - xa) * 2 - 1;
|
||
+ else if (xa - ((int) maxcol - xa) > xb)
|
||
+ n = maxcol - xb;
|
||
+ else
|
||
+ n = (xa - xb) * 2;
|
||
+ } else {
|
||
+ if (xb <= xa)
|
||
+ n = (xa - xb) * 2;
|
||
+ else if (2 * xa < xb)
|
||
+ n = xb;
|
||
+ else
|
||
+ n = (xb - xa) * 2 - 1;
|
||
+ }
|
||
+ pic2_arith_encode_nn(pi, n, xn);
|
||
+}
|
||
+
|
||
+static void pic2_arith_write_color(pi, x)
|
||
+struct pic2_info *pi;
|
||
+int x;
|
||
+{
|
||
+ pixel c1, c2, cc;
|
||
+ short g0, r0, b0, r, g, b;
|
||
+ int i, j;
|
||
+ unsigned short k;
|
||
+ pixel *p, *pp;
|
||
+ short colbits;
|
||
+ pixel rmask, gmask, bmask;
|
||
+ byte maxcol;
|
||
+
|
||
+ colbits = pi->header->depth / 3;
|
||
+ rmask = (0xff >> (8 - colbits)) << (colbits * 2);
|
||
+ gmask = (0xff >> (8 - colbits)) << colbits;
|
||
+ bmask = (0xff >> (8 - colbits));
|
||
+ maxcol = (byte) bmask;
|
||
+
|
||
+ cc = pi->vram_now[x];
|
||
+ c1 = pi->vram_prev[x];
|
||
+ k = ((c1 >> ((colbits - 3) * 3)) & 0x1c0)
|
||
+ | ((c1 >> ((colbits - 3) * 2)) & 0x038)
|
||
+ | ((c1 >> (colbits - 3) ) & 0x007);
|
||
+ if (colbits == 5)
|
||
+ k = pic2_exchange_rg(k, 3);
|
||
+
|
||
+ p = pi->cache[k];
|
||
+ for (i = 0; i < (PIC2_ARITH_CACHE - 1); i++) {
|
||
+ if (cc == *p++)
|
||
+ break;
|
||
+ }
|
||
+ if (i == (PIC2_ARITH_CACHE - 1)) {
|
||
+ pp = p - 1;
|
||
+ for (j = i; j > 0; j--) {
|
||
+ *--p = *--pp;
|
||
+ }
|
||
+ pi->cache[k][0] = cc;
|
||
+ pic2_arith_encode_bit(pi, 1, pi->cache_hit_c);
|
||
+ pi->cache_hit_c = 16;
|
||
+
|
||
+ c2 = pi->vram_now[x - 1];
|
||
+ r = ((c1 & rmask) + (c2 & rmask)) >> (colbits * 2 + 1);
|
||
+ g = ((c1 & gmask) + (c2 & gmask)) >> (colbits + 1);
|
||
+ b = ((c1 & bmask) + (c2 & bmask)) >> ( 1);
|
||
+
|
||
+ r0 = (cc >> (colbits * 2)) & maxcol;
|
||
+ g0 = (cc >> colbits ) & maxcol;
|
||
+ b0 = cc & maxcol;
|
||
+
|
||
+ r = r + g0 - g;
|
||
+ if (r < 0)
|
||
+ r = 0;
|
||
+ else if (r > (short) maxcol)
|
||
+ r = maxcol;
|
||
+
|
||
+ b = b + g0 - g;
|
||
+ if (b < 0)
|
||
+ b = 0;
|
||
+ else if (b > (short) maxcol)
|
||
+ b = maxcol;
|
||
+
|
||
+ pic2_arith_put_number(pi, 32, g, g0);
|
||
+ pic2_arith_put_number(pi, 48, r, r0);
|
||
+ pic2_arith_put_number(pi, 64, b, b0);
|
||
+ } else {
|
||
+ *--p = pi->cache[k][i / 2];
|
||
+ pi->cache[k][i / 2] = pi->cache[k][0];
|
||
+ pi->cache[k][0] = cc;
|
||
+
|
||
+ pic2_arith_encode_bit(pi, 0, pi->cache_hit_c);
|
||
+ pi->cache_hit_c = 15;
|
||
+ pic2_arith_encode_nn(pi, i, 17);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic2_arith_press_line2(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int x, xw, ymax;
|
||
+ pixel cc;
|
||
+
|
||
+ xw = pi->block->x_wid;
|
||
+ ymax = pi->block->y_wid -1;
|
||
+ cc = pi->vram_now[xw - 1]; /* last color */
|
||
+ pi->vram_next[-1] = cc;
|
||
+
|
||
+ /* mark change point */
|
||
+ for (x = 0; x < xw; x++)
|
||
+ if (cc != pi->vram_next[x]) {
|
||
+ pi->flag_next[x] = 1;
|
||
+ cc = pi->vram_next[x];
|
||
+ } else
|
||
+ pi->flag_next[x] = 0;
|
||
+
|
||
+ for (x = 0; x < xw; x++) {
|
||
+ if (pi->flag_now[x] == 1) { /* change point */
|
||
+ pi->flag2_now [x + 1]++;
|
||
+ pi->flag2_now [x + 2]++;
|
||
+ pi->flag2_next [x - 1]++;
|
||
+ pi->flag2_next [x ]++;
|
||
+ pi->flag2_next [x + 1]++;
|
||
+ pi->flag2_next2[x - 1]++;
|
||
+ pi->flag2_next2[x ]++;
|
||
+ pi->flag2_next2[x + 1]++;
|
||
+
|
||
+ /* write change point */
|
||
+ pic2_arith_encode_bit(pi, 1, pi->flag2_now[x]);
|
||
+
|
||
+ /* write color */
|
||
+ pic2_arith_write_color(pi, x);
|
||
+
|
||
+ /* if not last line, write chain */
|
||
+ if (pi->ynow - 1 < ymax)
|
||
+ pic2_arith_press_chain(pi, x);
|
||
+ } else if (pi->flag_now[x] == 0) /* not on chain */
|
||
+ /* write change point */
|
||
+ pic2_arith_encode_bit(pi, 0, pi->flag2_now[x]);
|
||
+ else /* on chain */
|
||
+ /* if not on last line, write next chain */
|
||
+ if (pi->ynow - 1 < ymax)
|
||
+ pic2_arith_press_chain(pi, x);
|
||
+ }
|
||
+}
|
||
+
|
||
+static int pic2_arith_press_line(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ int i, xw, ymax;
|
||
+ long *c_sum, *c_0_sum;
|
||
+
|
||
+ xw = pi->block->x_wid;
|
||
+ ymax = pi->block->y_wid -1;
|
||
+ c_sum = (long *) pi->mulu_tab;
|
||
+ c_0_sum = c_sum + PIC2_ARITH_CONTEXT +1;
|
||
+
|
||
+ pic2_handle_para(pi, 0);
|
||
+
|
||
+ xvbzero((char *) pi->flag2_next2 - 4,
|
||
+ (8 + xw) * sizeof(pi->flag2_next2[0]));
|
||
+
|
||
+ if (pi->ynow == 0) { /* first line */
|
||
+ int x;
|
||
+ pixel cc = 0;
|
||
+
|
||
+ if (pi->dd != 0) { /* compress pass */
|
||
+ unsigned short c_tab[PIC2_ARITH_CONTEXT];
|
||
+
|
||
+ for (i = 0; i < PIC2_ARITH_CONTEXT; i++) {
|
||
+ unsigned long a, b;
|
||
+ a = c_0_sum[i];
|
||
+ b = c_sum[i];
|
||
+ while (a > 32767) {
|
||
+ a /= 2;
|
||
+ b /= 2;
|
||
+ }
|
||
+ if (a == b)
|
||
+ c_tab[i] = 0xffff; /* b==0 here, too */
|
||
+ else
|
||
+ c_tab[i] = (65536 * a) / b; /* a < b, so less 65536 */
|
||
+ }
|
||
+ for (i = 0; i < 16384; i++) {
|
||
+ pi->mulu_tab[i] = (long) (i / 128 + 128) * (int) c_tab[i & 127] / 256;
|
||
+ if (pi->mulu_tab[i] == 0)
|
||
+ pi->mulu_tab[i] = 1; /* 0 is wrong */
|
||
+ }
|
||
+ for (i = 0; i < PIC2_ARITH_CONTEXT; i++)
|
||
+ pic2_write_short(pi, c_tab[i]);
|
||
+
|
||
+ xvbzero((char *) pi->vram_now, xw * sizeof(pi->vram_now[0]));
|
||
+ } else { /* statistical pass */
|
||
+ xvbzero((char *) c_0_sum, PIC2_ARITH_CONTEXT * sizeof(c_0_sum[0]));
|
||
+ xvbzero((char *) c_sum, PIC2_ARITH_CONTEXT * sizeof(c_sum[0]));
|
||
+ }
|
||
+
|
||
+ /* initialize flags */
|
||
+ xvbzero((char *) pi->cache, 8 * 8 * 8 * sizeof(pi->cache[0]));
|
||
+ xvbzero((char *) pi->cache_pos, 8 * 8 * 8 * sizeof(pi->cache_pos[0]));
|
||
+
|
||
+ xvbzero((char *) pi->flag2_next - 4,
|
||
+ (8 + xw) * sizeof(pi->flag2_next[0]));
|
||
+ xvbzero((char *) pi->flag2_next2 - 4,
|
||
+ (8 + xw) * sizeof(pi->flag2_next2[0]));
|
||
+
|
||
+ pi->vram_next[-1] = cc;
|
||
+ for (x = 0; x < xw; x++)
|
||
+ if (cc != pi->vram_next[x]) {
|
||
+ pi->flag_next[x] = 1;
|
||
+ cc = pi->vram_next[x];
|
||
+ } else
|
||
+ pi->flag_next[x] = 0;
|
||
+
|
||
+ pi->aa = 0xffff;
|
||
+ cc = 0;
|
||
+ pi->cache_hit_c = 16;
|
||
+ } else /* after second line */
|
||
+ pic2_arith_press_line2(pi);
|
||
+
|
||
+ if (pi->ynow == ymax) {
|
||
+ pi->ynow++;
|
||
+ pic2_handle_para(pi, 1);
|
||
+ pic2_handle_para(pi, 0);
|
||
+ pic2_arith_press_line2(pi);
|
||
+ }
|
||
+ /* line buffer for next data */
|
||
+ if (line != NULL)
|
||
+ *line = pi->vram_prev;
|
||
+
|
||
+ pi->ynow++;
|
||
+
|
||
+ if (pi->ynow - 1 < ymax) {
|
||
+ pic2_handle_para(pi, 1);
|
||
+ return (pi->ynow);
|
||
+ } else { /* end */
|
||
+ if (pi->dd == 0) { /* statistical pass */
|
||
+ pi->dd = 1;
|
||
+ pi->ynow = 0;
|
||
+ pic2_handle_para(pi, 1);
|
||
+ return (0);
|
||
+ } else {
|
||
+ pic2_handle_para(pi, 1);
|
||
+ pic2_arith_flush_bit_buf(pi);
|
||
+ return (-2); /* end */
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static int pic2_arith_saver_init(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ pi->ynow = 0;
|
||
+
|
||
+ /* check the color depth */
|
||
+ if (pi->header->depth % 3)
|
||
+ pic2_error(pi, PIC2_DEPTH);
|
||
+
|
||
+ /* set next line function */
|
||
+ pi->next_line = pic2_arith_press_line;
|
||
+
|
||
+ if (line != NULL)
|
||
+ *line = pi->vram_next + 4;
|
||
+
|
||
+ pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
|
||
+
|
||
+ /* clear bit field marker */
|
||
+ pi->bs.rest = 0;
|
||
+ pi->bs.cur = 0;
|
||
+ pi->bs.zero = 0;
|
||
+ pi->bs.bits = 0;
|
||
+
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions are fast pic2 format compressor.
|
||
+ */
|
||
+static void pic2_fast_write_length(pi, n)
|
||
+struct pic2_info *pi;
|
||
+int n;
|
||
+{
|
||
+ int a, b;
|
||
+ static const unsigned short len_data[8][2] = {
|
||
+ {1, 0},
|
||
+ {1, 0},
|
||
+ {3, 4},
|
||
+ {3, 5},
|
||
+ {5, 24},
|
||
+ {5, 25},
|
||
+ {5, 26},
|
||
+ {5, 27},
|
||
+ };
|
||
+
|
||
+ n++;
|
||
+ if (n < 8)
|
||
+ pic2_write_bits(pi, len_data[n][1], len_data[n][0]);
|
||
+ else {
|
||
+ a = 0;
|
||
+ b = 2;
|
||
+ while (n > b - 1) {
|
||
+ a = a + 1;
|
||
+ b = b * 2;
|
||
+ }
|
||
+ pic2_write_bits(pi, 0xfffffffe, a + 1);
|
||
+ if (a > 0)
|
||
+ pic2_write_bits(pi, n - b / 2, a);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic2_fast_press_chain(pi, x)
|
||
+struct pic2_info *pi;
|
||
+int x;
|
||
+{
|
||
+ int ymax;
|
||
+ pixel cc;
|
||
+
|
||
+ ymax = pi->block->y_wid -1;
|
||
+ cc = pi->vram_now[x];
|
||
+
|
||
+ if (pi->ynow - 1 == ymax) {
|
||
+ pic2_write_bits(pi, 0, 1);
|
||
+ return;
|
||
+ }
|
||
+ if (pi->flag_next[x] == 1 && pi->vram_next[x] == cc) {
|
||
+ pi->flag_next[x] = -1;
|
||
+ pic2_write_bits(pi, 3, 2);
|
||
+ } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == cc) {
|
||
+ pi->flag_next[x - 1] = -1;
|
||
+ pic2_write_bits(pi, 11, 4);
|
||
+ } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == cc) {
|
||
+ pi->flag_next[x + 1] = -1;
|
||
+ pic2_write_bits(pi, 9, 4);
|
||
+ } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == cc) {
|
||
+ pi->flag_next[x - 2] = -1;
|
||
+ pic2_write_bits(pi, 10, 4);
|
||
+ } else if ((pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == cc)
|
||
+ && !(pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == cc)) {
|
||
+ pi->flag_next[x + 2] = -1;
|
||
+ pic2_write_bits(pi, 8, 4);
|
||
+ } else
|
||
+ pic2_write_bits(pi, 0, 1);
|
||
+}
|
||
+
|
||
+static void pic2_fast_press_chain2(pi, x)
|
||
+struct pic2_info *pi;
|
||
+int x;
|
||
+{
|
||
+ int ymax;
|
||
+ pixel cc;
|
||
+ char *chain_buff;
|
||
+
|
||
+ ymax = pi->block->y_wid -1;
|
||
+ chain_buff = (char *) pi->mulu_tab;
|
||
+ cc = pi->vram_now[x];
|
||
+
|
||
+ if (pi->ynow - 1 == ymax) {
|
||
+ chain_buff[pi->cc++] = 0;
|
||
+ return;
|
||
+ }
|
||
+ if (pi->flag_next[x] == 1 && pi->vram_next[x] == cc) {
|
||
+ pi->flag_next[x] = -1;
|
||
+ chain_buff[pi->cc++] = 1;
|
||
+ } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == cc) {
|
||
+ pi->flag_next[x - 1] = -1;
|
||
+ chain_buff[pi->cc++] = 2;
|
||
+ } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == cc) {
|
||
+ pi->flag_next[x + 1] = -1;
|
||
+ chain_buff[pi->cc++] = 3;
|
||
+ } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == cc) {
|
||
+ pi->flag_next[x - 2] = -1;
|
||
+ chain_buff[pi->cc++] = 4;
|
||
+ } else if ((pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == cc)
|
||
+ && !(pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == cc)) {
|
||
+ pi->flag_next[x + 2] = -1;
|
||
+ chain_buff[pi->cc++] = 5;
|
||
+ } else
|
||
+ chain_buff[pi->cc++] = 0;
|
||
+}
|
||
+
|
||
+static void pic2_fast_flush_chain(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int i;
|
||
+ char *chain_buf;
|
||
+
|
||
+ chain_buf = (char *) pi->mulu_tab;
|
||
+ for (i = 0; i < pi->cc; i++){
|
||
+ switch (chain_buf[i]) {
|
||
+ case 0:
|
||
+ pic2_write_bits(pi, 0, 1);
|
||
+ break;
|
||
+ case 1:
|
||
+ pic2_write_bits(pi, 3, 2);
|
||
+ break;
|
||
+ case 2:
|
||
+ pic2_write_bits(pi, 11, 4);
|
||
+ break;
|
||
+ case 3:
|
||
+ pic2_write_bits(pi, 9, 4);
|
||
+ break;
|
||
+ case 4:
|
||
+ pic2_write_bits(pi, 10, 4);
|
||
+ break;
|
||
+ case 5:
|
||
+ pic2_write_bits(pi, 8, 4);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ pi->cc = 0;
|
||
+}
|
||
+
|
||
+static void pic2_fast_write_color(pi, x)
|
||
+struct pic2_info *pi;
|
||
+int x;
|
||
+{
|
||
+ pixel cc, bc;
|
||
+ unsigned short j, k, m;
|
||
+ short depth, colbits;
|
||
+ pixel (*cache)[PIC2_FAST_CACHE];
|
||
+
|
||
+ depth = pi->header->depth;
|
||
+ colbits = depth / 3;
|
||
+ cache = (pixel (*)[PIC2_FAST_CACHE]) pi->cache;
|
||
+
|
||
+ bc = pi->vram_now[x - 1];
|
||
+ bc = pic2_exchange_rg(bc, colbits);
|
||
+ k = pic2_shift_bits(bc, 8 - depth);
|
||
+ cc = pi->vram_now[x];
|
||
+ m = pi->cache_pos[k];
|
||
+
|
||
+ for (j = 0; j < PIC2_FAST_CACHE; j++)
|
||
+ if (cache[k][(m + j) & (PIC2_FAST_CACHE - 1)] == cc)
|
||
+ break;
|
||
+
|
||
+ if (j == PIC2_FAST_CACHE) {
|
||
+ m = (m - 1) & (PIC2_FAST_CACHE - 1);
|
||
+ pi->cache_pos[k] = m;
|
||
+ cache[k][m] = cc;
|
||
+
|
||
+ cc = pic2_exchange_rg(cc, colbits);
|
||
+ pic2_write_bits(pi, 0, 1);
|
||
+ pic2_write_bits(pi, cc, depth);
|
||
+ } else {
|
||
+ pic2_write_bits(pi, 1, 1);
|
||
+ pic2_write_bits(pi, j, 6);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic2_fast_press_line2(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int x, xw;
|
||
+ pixel cc;
|
||
+
|
||
+ xw = pi->block->x_wid;
|
||
+ cc = pi->vram_now[xw - 1]; /* last color */
|
||
+ pi->vram_next[-1] = cc;
|
||
+
|
||
+ /* mark change point */
|
||
+ for (x = 0; x < xw; x++)
|
||
+ if (cc != pi->vram_next[x]) {
|
||
+ pi->flag_next[x] = 1;
|
||
+ cc = pi->vram_next[x];
|
||
+ } else
|
||
+ pi->flag_next[x] = 0;
|
||
+
|
||
+ for (x = 0; x < xw; x++)
|
||
+ if (pi->flag_now[x] == 1) { /* change point */
|
||
+ if (pi->aa >= 1023)
|
||
+ pi->aa++;
|
||
+ pic2_fast_write_length(pi, pi->aa);
|
||
+ pic2_fast_flush_chain(pi);
|
||
+ pi->aa = 0;
|
||
+ pic2_fast_write_color(pi, x);
|
||
+ pic2_fast_press_chain(pi, x);
|
||
+ } else if (pi->flag_now[x] == 0) {
|
||
+ pi->aa++;
|
||
+ } else {
|
||
+ pic2_fast_press_chain2(pi, x);
|
||
+ if (pi->cc == 1023) {
|
||
+ pic2_fast_write_length(pi, 1023);
|
||
+ pic2_fast_flush_chain(pi);
|
||
+ pi->aa = 0;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static int pic2_fast_press_line(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ int xw, ymax;
|
||
+
|
||
+ xw = pi->block->x_wid;
|
||
+ ymax = pi->block->y_wid -1;
|
||
+
|
||
+ pic2_handle_para(pi, 0);
|
||
+
|
||
+ if (pi->ynow == 0) { /* first line */
|
||
+ int x;
|
||
+ pixel cc = 0;
|
||
+
|
||
+ /* initialize flags */
|
||
+ xvbzero((char *) pi->cache, 256 * sizeof(pi->cache[0]));
|
||
+ xvbzero((char *) pi->cache_pos,
|
||
+ PIC2_FAST_CACHE * sizeof(pi->cache_pos[0]));
|
||
+
|
||
+ /* mark change point */
|
||
+ pi->vram_next[-1] = cc;
|
||
+ for (x = 0; x < xw; x++)
|
||
+ if (cc != pi->vram_next[x]) {
|
||
+ pi->flag_next[x] = 1;
|
||
+ cc = pi->vram_next[x];
|
||
+ } else
|
||
+ pi->flag_next[x] = 0;
|
||
+
|
||
+ pi->cc = 0;
|
||
+ pi->aa = 0;
|
||
+ } else /* after second line */
|
||
+ pic2_fast_press_line2(pi);
|
||
+
|
||
+ if (pi->ynow == ymax) {
|
||
+ pi->ynow++;
|
||
+ pic2_handle_para(pi, 1);
|
||
+ pic2_handle_para(pi, 0);
|
||
+ pic2_fast_press_line2(pi);
|
||
+ }
|
||
+ /* line buffer for next data */
|
||
+ if (line != NULL)
|
||
+ *line = pi->vram_prev;
|
||
+
|
||
+ pi->ynow++;
|
||
+
|
||
+ if (pi->ynow - 1 < ymax) {
|
||
+ pic2_handle_para(pi, 1);
|
||
+ return (pi->ynow);
|
||
+ } else { /* end */
|
||
+ pic2_handle_para(pi, 1);
|
||
+ if (pi->aa >= 1023)
|
||
+ pi->aa++;
|
||
+ pic2_fast_write_length(pi, pi->aa);
|
||
+ pic2_fast_flush_chain(pi);
|
||
+ return (-2); /* end */
|
||
+ }
|
||
+}
|
||
+
|
||
+static int pic2_fast_saver_init(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ pi->ynow = 0;
|
||
+
|
||
+ /* check the color depth */
|
||
+ if (pi->header->depth % 3)
|
||
+ pic2_error(pi, PIC2_DEPTH);
|
||
+
|
||
+ /* set next line function */
|
||
+ pi->next_line = pic2_fast_press_line;
|
||
+ if (line != NULL)
|
||
+ *line = pi->vram_next + 4;
|
||
+
|
||
+ pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
|
||
+
|
||
+ /* clear bit field marker */
|
||
+ pi->bs.rest = 0;
|
||
+ pi->bs.cur = 0;
|
||
+
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions are beta pic2 format compressor.
|
||
+ */
|
||
+static int pic2_beta_press_line(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ int i, xw, ymax;
|
||
+ byte *p;
|
||
+ pixel *pc;
|
||
+ short depth, pixbyte, colbits;
|
||
+
|
||
+ depth = pi->header->depth;
|
||
+ pixbyte = depth / 8 + ((depth % 8) > 0);
|
||
+ colbits = depth / 3;
|
||
+
|
||
+ xw = pi->block->x_wid;
|
||
+ ymax = pi->block->y_wid - 1;
|
||
+
|
||
+ pc = pi->vram_now;
|
||
+ p = (byte *) pi->vram_prev;
|
||
+ if (pixbyte == 3) {
|
||
+ for (i = 0; i < xw; i++, pc++) {
|
||
+ *p++ = *pc >> 16;
|
||
+ *p++ = *pc >> 8;
|
||
+ *p++ = *pc;
|
||
+ }
|
||
+ pic2_write_file(pi, pi->vram_prev, (size_t) (xw * 3));
|
||
+ } else if (pixbyte == 2) {
|
||
+ if (strncmp(pi->block->id, "P2BM", 4) == 0)
|
||
+ for (i = 0; i < xw; i++, pc++) {
|
||
+ if (colbits == 5) {
|
||
+ *pc = pic2_exchange_rg(*pc, colbits);
|
||
+ *pc <<= 1;
|
||
+ }
|
||
+ *p++ = *pc >> 8;
|
||
+ *p++ = *pc;
|
||
+ }
|
||
+ else
|
||
+ for (i = 0; i < xw; i++, pc++) {
|
||
+ if (colbits == 5) {
|
||
+ *pc = pic2_exchange_rg(*pc, colbits);
|
||
+ *pc <<= 1;
|
||
+ }
|
||
+ *p++ = *pc;
|
||
+ *p++ = *pc >> 8;
|
||
+ }
|
||
+ pic2_write_file(pi, pi->vram_prev, (size_t) (xw * 2));
|
||
+ } else {
|
||
+ for (i = 0; i < xw; i++, pc++)
|
||
+ *p++ = *pc;
|
||
+ pic2_write_file(pi, pi->vram_prev, (size_t) xw);
|
||
+ }
|
||
+ if (line != NULL)
|
||
+ *line = pi->vram_now;
|
||
+
|
||
+ pi->ynow++;
|
||
+ if (pi->ynow > ymax)
|
||
+ return (-2);
|
||
+ return (pi->ynow);
|
||
+}
|
||
+
|
||
+static int pic2_beta_saver_init(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ pi->ynow = 0;
|
||
+
|
||
+ *line = pi->vram_now;
|
||
+ pi->next_line = pic2_beta_press_line;
|
||
+ pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function saves compressed data.
|
||
+ */
|
||
+static void pic2_write_data(pi, data, ptype, x_offset, y_offset, w, h,
|
||
+ rmap, gmap, bmap, type, depth)
|
||
+struct pic2_info *pi;
|
||
+byte *data;
|
||
+int ptype;
|
||
+int x_offset, y_offset;
|
||
+int w, h;
|
||
+byte *rmap, *gmap, *bmap;
|
||
+int type, depth;
|
||
+{
|
||
+ int i, line;
|
||
+ pixel *linep;
|
||
+ short colbits;
|
||
+
|
||
+ colbits = pi->header->depth / 3;
|
||
+
|
||
+ line = pic2_save_block(pi, &linep, x_offset, y_offset, w, h,
|
||
+ form_tab[type].id, 0xffffffff);
|
||
+ while (line >= 0) {
|
||
+ byte r, g, b;
|
||
+ int pic_idx;
|
||
+
|
||
+ pic_idx = line * w * ((ptype == PIC24) ? 3 : 1);
|
||
+
|
||
+ for (i = 0; i < w; i++) {
|
||
+ if (ptype != PIC24) {
|
||
+ r = rmap[data[pic_idx]];
|
||
+ g = gmap[data[pic_idx]];
|
||
+ b = bmap[data[pic_idx]];
|
||
+ pic_idx++;
|
||
+ } else {
|
||
+ r = data[pic_idx++];
|
||
+ g = data[pic_idx++];
|
||
+ b = data[pic_idx++];
|
||
+ }
|
||
+ if (pi->writing_grey)
|
||
+ r = g = b = MONO(r, g, b);
|
||
+
|
||
+ r = pic2_convert_color_bits(r, 8, colbits);
|
||
+ g = pic2_convert_color_bits(g, 8, colbits);
|
||
+ b = pic2_convert_color_bits(b, 8, colbits);
|
||
+
|
||
+ linep[i] = ((pixel) r << (colbits * 2))
|
||
+ | ((pixel) g << colbits )
|
||
+ | ((pixel) b );
|
||
+ }
|
||
+ line = pic2_next_line(pi, &linep);
|
||
+ WaitCursor();
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function compresses/extracts one line buffer.
|
||
+ */
|
||
+static int pic2_next_line(pi, line)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+{
|
||
+ int res;
|
||
+
|
||
+ res = pi->next_line(pi, line);
|
||
+ if (res == -2) {
|
||
+ if (pi->mode == PIC2_WRITE_MODE) {
|
||
+ long new_pos;
|
||
+
|
||
+ new_pos = pic2_tell_file(pi);
|
||
+ pi->block->size = new_pos - pi->next_pos;
|
||
+ pic2_seek_file(pi, pi->next_pos, SEEK_SET);
|
||
+ pic2_write_block_header(pi);
|
||
+ pi->next_pos = new_pos;
|
||
+ if (DEBUG)
|
||
+ pic2_show_pic2_info(pi);
|
||
+ }
|
||
+ pic2_free_buffer(pi);
|
||
+ }
|
||
+ return (res);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions find the pic2 image block.
|
||
+ * pic2_next_block:
|
||
+ * moves the file pointer to the next image block.
|
||
+ * pic2_find_block:
|
||
+ * finds the first image block and moves the file pointer there.
|
||
+ */
|
||
+static int pic2_next_block(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ if (pi->mode != PIC2_READ_MODE)
|
||
+ return (-1);
|
||
+
|
||
+ /* go to block for read */
|
||
+ pic2_seek_file(pi, pi->next_pos, SEEK_SET);
|
||
+
|
||
+ /* read the head of block header */
|
||
+ pic2_read_block_header1(pi);
|
||
+
|
||
+ /* end block ? */
|
||
+ if (pi->block->id[0] == 0)
|
||
+ return (0);
|
||
+
|
||
+ /* set current block */
|
||
+ pi->block_pos = pi->next_pos;
|
||
+
|
||
+ /* set next block */
|
||
+ pi->next_pos += pi->block->size;
|
||
+
|
||
+ /* check block id */
|
||
+ for (i = 0; i < n_form_tab; i++) {
|
||
+ if (xvbcmp(pi->block->id, form_tab[i].id, (size_t) 4) == 0)
|
||
+ break;
|
||
+ }
|
||
+ if (i == n_form_tab)
|
||
+ return (2);
|
||
+
|
||
+ /* read the rest of block header */
|
||
+ pic2_read_block_header2(pi);
|
||
+
|
||
+ if (pi->block->x_offset + pi->block->x_wid > pi->x_max)
|
||
+ pi->x_max = pi->block->x_offset + pi->block->x_wid;
|
||
+
|
||
+ if (pi->block->y_offset + pi->block->y_wid > pi->y_max)
|
||
+ pi->y_max = pi->block->y_offset + pi->block->y_wid;
|
||
+
|
||
+ if (DEBUG)
|
||
+ pic2_show_pic2_info(pi);
|
||
+ return (1);
|
||
+}
|
||
+
|
||
+static int pic2_find_block(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ if (pi->mode != PIC2_READ_MODE)
|
||
+ return (-1);
|
||
+
|
||
+ pi->next_pos = pi->header->size;
|
||
+ return (pic2_next_block(pi));
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions load/save the pic2 image block.
|
||
+ * pic2_load_block:
|
||
+ * initializes loader information with current block information.
|
||
+ * pic2_save_block:
|
||
+ * initializes saver information.
|
||
+ */
|
||
+static int pic2_load_block(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < n_form_tab; i++) {
|
||
+ if (xvbcmp(pi->block->id, form_tab[i].id, (size_t) 4) == 0)
|
||
+ break;
|
||
+ }
|
||
+ if (i == n_form_tab)
|
||
+ return (2);
|
||
+
|
||
+ pic2_alloc_buffer(pi);
|
||
+ return (form_tab[i].loader_init(pi));
|
||
+}
|
||
+
|
||
+static int pic2_save_block(pi, line, x, y, xw, yw, id, opaque)
|
||
+struct pic2_info *pi;
|
||
+pixel **line;
|
||
+int x, y, xw, yw;
|
||
+char *id;
|
||
+pixel opaque;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < n_form_tab; i++) {
|
||
+ if (xvbcmp(id, form_tab[i].id, (size_t) 4) == 0)
|
||
+ break;
|
||
+ }
|
||
+ if (i == n_form_tab)
|
||
+ return (2);
|
||
+
|
||
+ strncpy(pi->block->id, id, 4);
|
||
+ pi->block->x_wid = xw;
|
||
+ pi->block->y_wid = yw;
|
||
+ pi->block->x_offset = x;
|
||
+ pi->block->y_offset = y;
|
||
+ pi->block->reserve = 0;
|
||
+
|
||
+ if (x < 0)
|
||
+ x = 0;
|
||
+ if (y < 0)
|
||
+ y = 0;
|
||
+ if (x + xw > pi->x_max)
|
||
+ pi->x_max = x + xw;
|
||
+ if (y + yw > pi->y_max)
|
||
+ pi->y_max = y + yw;
|
||
+
|
||
+ if (opaque != 0xffffffff) {
|
||
+ pi->block->flag = 1;
|
||
+ pi->block->opaque = opaque;
|
||
+ } else {
|
||
+ pi->block->flag = 0;
|
||
+ pi->block->opaque = 0;
|
||
+ }
|
||
+ pic2_alloc_buffer(pi);
|
||
+
|
||
+ return (form_tab[i].saver_init(pi, line));
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions set/get palettes.
|
||
+ * pic2_read_palette:
|
||
+ * copy the palettes from pic2_info to PICINFO.
|
||
+ * pic2_write_palette:
|
||
+ * copy the palettes from PICINFO to pic2_info.
|
||
+ */
|
||
+#ifndef PIC2_IGNORE_UNUSED_FUNCTIONS
|
||
+static void pic2_read_palette(pi, r, g, b)
|
||
+struct pic2_info *pi;
|
||
+byte *r, *g, *b;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ if (pi->n_pal > 256)
|
||
+ pi->n_pal = 256;
|
||
+
|
||
+ if (pi->pal_bits > 8)
|
||
+ pi->pal_bits = 8;
|
||
+
|
||
+ for (i = 0; i < pi->n_pal; i++) {
|
||
+ *r++ =pic2_convert_color_bits(pi->pal[i][0] >> (8 - pi->pal_bits),
|
||
+ pi->pal_bits, 8);
|
||
+ *g++ =pic2_convert_color_bits(pi->pal[i][1] >> (8 - pi->pal_bits),
|
||
+ pi->pal_bits, 8);
|
||
+ *b++ =pic2_convert_color_bits(pi->pal[i][2] >> (8 - pi->pal_bits),
|
||
+ pi->pal_bits, 8);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic2_write_palette(pi, n_pal, pal_bits, r, g, b)
|
||
+struct pic2_info *pi;
|
||
+int n_pal, pal_bits;
|
||
+byte *r, *g, *b;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ if (n_pal > 256)
|
||
+ pi->n_pal = 256;
|
||
+ else
|
||
+ pi->n_pal = n_pal;
|
||
+
|
||
+ if (pal_bits > 8)
|
||
+ pi->pal_bits = 8;
|
||
+ else
|
||
+ pi->pal_bits = pal_bits;
|
||
+
|
||
+ for (i = 0; i < n_pal; i++) {
|
||
+ pi->pal[i][0] = pic2_convert_color_bits(*r++, 8, pal_bits)
|
||
+ << (8 - pal_bits);
|
||
+ pi->pal[i][1] = pic2_convert_color_bits(*g++, 8, pal_bits)
|
||
+ << (8 - pal_bits);
|
||
+ pi->pal[i][2] = pic2_convert_color_bits(*b++, 8, pal_bits)
|
||
+ << (8 - pal_bits);
|
||
+ }
|
||
+}
|
||
+#endif /* PIC2_IGNORE_UNUSED_FUNCTIONS */
|
||
+
|
||
+/*
|
||
+ * These functions handle color bits.
|
||
+ * pic2_convert_color_bits:
|
||
+ * converts color bits.
|
||
+ * pic2_pad_color_bits:
|
||
+ * pads color bits.
|
||
+ * pic2_reduce_color_bits:
|
||
+ * reduces color bits.
|
||
+ * pic2_exchange_rg:
|
||
+ * exchanges red and green values.
|
||
+ */
|
||
+static byte pic2_convert_color_bits(c, from, to)
|
||
+int c, from, to;
|
||
+{
|
||
+ if (from == to)
|
||
+ return ((byte) c);
|
||
+ else if (from < to)
|
||
+ return (pic2_pad_color_bits(c, from, to));
|
||
+ else
|
||
+ return (pic2_reduce_color_bits(c, from, to));
|
||
+}
|
||
+
|
||
+static byte pic2_pad_color_bits(c, from, to)
|
||
+int c, from, to;
|
||
+{
|
||
+ byte p = 0;
|
||
+
|
||
+ do {
|
||
+ to -= from;
|
||
+ p |= pic2_shift_bits(c, to);
|
||
+ } while (to >= 0);
|
||
+ return (p);
|
||
+}
|
||
+
|
||
+static byte pic2_reduce_color_bits(c, from, to)
|
||
+int c, from, to;
|
||
+{
|
||
+ return ((byte) (c >> (from - to)));
|
||
+}
|
||
+
|
||
+static pixel pic2_exchange_rg(p, colbits)
|
||
+pixel p;
|
||
+int colbits;
|
||
+{
|
||
+ pixel rmask, gmask, bmask;
|
||
+
|
||
+ rmask = (0xff >> (8 - colbits)) << (colbits * 2);
|
||
+ gmask = (0xff >> (8 - colbits)) << colbits;
|
||
+ bmask = (0xff >> (8 - colbits));
|
||
+
|
||
+ p = ((p << colbits) & rmask)
|
||
+ | ((p >> colbits) & gmask)
|
||
+ | ( p & bmask);
|
||
+ return (p);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function handles work memory buffer.
|
||
+ */
|
||
+static void pic2_handle_para(pi, mode)
|
||
+struct pic2_info *pi;
|
||
+int mode;
|
||
+{
|
||
+ static pixel *vram_prev, *vram_now, *vram_next;
|
||
+ static short *flag_now, *flag_next;
|
||
+ static short *flag2_now, *flag2_next, *flag2_next2;
|
||
+
|
||
+ switch (mode) {
|
||
+ case 0:
|
||
+ vram_prev = pi->vram_prev;
|
||
+ vram_now = pi->vram_now;
|
||
+ vram_next = pi->vram_next;
|
||
+ flag_now = pi->flag_now;
|
||
+ flag_next = pi->flag_next;
|
||
+ flag2_now = pi->flag2_now;
|
||
+ flag2_next = pi->flag2_next;
|
||
+ flag2_next2 = pi->flag2_next2;
|
||
+ pi->vram_prev += 4;
|
||
+ pi->vram_now += 4;
|
||
+ pi->vram_next += 4;
|
||
+ pi->flag_now += 4;
|
||
+ pi->flag_next += 4;
|
||
+ pi->flag2_now += 4;
|
||
+ pi->flag2_next += 4;
|
||
+ pi->flag2_next2 += 4;
|
||
+ break;
|
||
+ case 1:
|
||
+ pi->vram_prev = vram_now;
|
||
+ pi->vram_now = vram_next;
|
||
+ pi->vram_next = vram_prev;
|
||
+ pi->flag_now = flag_next;
|
||
+ pi->flag_next = flag_now;
|
||
+ pi->flag2_now = flag2_next;
|
||
+ pi->flag2_next = flag2_next2;
|
||
+ pi->flag2_next2 = flag2_now;
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions alloc/free work memory.
|
||
+ * pic2_alloc_buffer:
|
||
+ * alloc work memory buffer.
|
||
+ * pic2_free_buffer:
|
||
+ * free work memory buffer.
|
||
+ */
|
||
+static int pic2_alloc_buffer(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int wid;
|
||
+ byte *p;
|
||
+
|
||
+ if (pi->buf != NULL)
|
||
+ return (-1);
|
||
+
|
||
+ wid = pi->block->x_wid;
|
||
+
|
||
+ p = pi->buf = (byte *) pic2_new((wid + 8) * sizeof(pixel) * 3 // GRR POSSIBLE OVERFLOW / FIXME
|
||
+ + sizeof(pi->cache[0]) * 8 * 8 * 8
|
||
+ + sizeof(pi->cache_pos[0]) * 8 * 8 * 8
|
||
+ + sizeof(pi->mulu_tab[0]) * 16384
|
||
+ + sizeof(pi->flag_now[0]) * ((wid+8) * 5),
|
||
+ "pic2_alloc_buffer");
|
||
+
|
||
+ pi->vram_prev = (pixel *) p;
|
||
+ p += (wid + 8) * sizeof(pixel);
|
||
+ pi->vram_now = (pixel *) p;
|
||
+ p += (wid + 8) * sizeof(pixel);
|
||
+ pi->vram_next = (pixel *) p;
|
||
+ p += (wid + 8) * sizeof(pixel);
|
||
+ pi->cache = (pixel (*)[PIC2_ARITH_CACHE]) p;
|
||
+ p += sizeof(pi->cache[0]) * 8 * 8 * 8;
|
||
+ pi->cache_pos = (unsigned short *) p;
|
||
+ p += sizeof(pi->cache_pos[0]) * 8 * 8 * 8;
|
||
+ pi->mulu_tab = (unsigned short *) p;
|
||
+ p += sizeof(pi->mulu_tab[0]) * 16384;
|
||
+ pi->flag_now = (short *) p;
|
||
+ p += sizeof(pi->flag_now[0]) * (wid + 8);
|
||
+ pi->flag_next = (short *) p;
|
||
+ p += sizeof(pi->flag_next[0]) * (wid + 8);
|
||
+ pi->flag2_now = (short *) p;
|
||
+ p += sizeof(pi->flag2_now[0]) * (wid + 8);
|
||
+ pi->flag2_next = (short *) p;
|
||
+ p += sizeof(pi->flag2_next[0]) * (wid + 8);
|
||
+ pi->flag2_next2 = (short *) p;
|
||
+ p += sizeof(pi->flag2_next2[0]) * (wid + 8);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+static void pic2_free_buffer(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ free(pi->buf);
|
||
+ pi->buf = NULL;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions handle the file pointer.
|
||
+ * pic2_seek_file:
|
||
+ * moves the file pointer.
|
||
+ * pic2_tell_file:
|
||
+ * tells the location of the file pointer.
|
||
+ */
|
||
+static long pic2_seek_file(pi, offset, whence)
|
||
+struct pic2_info *pi;
|
||
+long offset;
|
||
+int whence;
|
||
+{
|
||
+ long n;
|
||
+
|
||
+ n = fseek(pi->fp, offset, whence);
|
||
+ if (n < 0)
|
||
+ pic2_file_error(pi, PIC2_CORRUPT);
|
||
+
|
||
+ return (n);
|
||
+}
|
||
+
|
||
+static long pic2_tell_file(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ return (ftell(pi->fp));
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions handle file.
|
||
+ * pic2_read_file:
|
||
+ * reads data from the file.
|
||
+ * pic2_read_long:
|
||
+ * reads long word data from the file and converts to internal expression.
|
||
+ * pic2_read_short:
|
||
+ * reads word data from the file and converts to internal expression.
|
||
+ * pic2_read_char:
|
||
+ * reads byte data from the file.
|
||
+ * pic2_write_file:
|
||
+ * writes data to the file.
|
||
+ * pic2_write_long:
|
||
+ * converts long word data to common expression and writes to the file.
|
||
+ * pic2_write_short:
|
||
+ * converts word data to common expression and writes to the file.
|
||
+ * pic2_write_char:
|
||
+ * writes byte data to the file.
|
||
+ */
|
||
+static int pic2_read_file(pi, buf, size)
|
||
+struct pic2_info *pi;
|
||
+void *buf;
|
||
+size_t size;
|
||
+{
|
||
+ if (fread(buf, (size_t) 1, size, pi->fp) < size)
|
||
+ pic2_file_error(pi, PIC2_CORRUPT);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+static long pic2_read_long(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ byte buf[4];
|
||
+
|
||
+ if (fread(buf, (size_t) 4, (size_t) 1, pi->fp) < 1)
|
||
+ pic2_file_error(pi, PIC2_CORRUPT);
|
||
+ return (pic2_cextolong(buf));
|
||
+}
|
||
+
|
||
+static short pic2_read_short(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ byte buf[2];
|
||
+
|
||
+ if (fread(buf, (size_t) 2, (size_t) 1, pi->fp) < 1)
|
||
+ pic2_file_error(pi, PIC2_CORRUPT);
|
||
+ return (pic2_cextoshort(buf));
|
||
+}
|
||
+
|
||
+static char pic2_read_char(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ int c;
|
||
+
|
||
+ if ((c = fgetc(pi->fp)) == EOF)
|
||
+ pic2_file_error(pi, PIC2_CORRUPT);
|
||
+ return ((char) c);
|
||
+}
|
||
+
|
||
+static int pic2_write_file(pi, buf, size)
|
||
+struct pic2_info *pi;
|
||
+void *buf;
|
||
+size_t size;
|
||
+{
|
||
+ if (fwrite(buf, (size_t) 1, size, pi->fp) < size)
|
||
+ pic2_error(pi, PIC2_WRITE);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+static int pic2_write_long(pi, n)
|
||
+struct pic2_info *pi;
|
||
+long n;
|
||
+{
|
||
+ byte buf[4];
|
||
+
|
||
+ pic2_longtocex(buf, n);
|
||
+ if (fwrite(buf, (size_t) 4, (size_t) 1, pi->fp) < 1)
|
||
+ pic2_error(pi, PIC2_WRITE);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+static int pic2_write_short(pi, n)
|
||
+struct pic2_info *pi;
|
||
+int n;
|
||
+{
|
||
+ byte buf[2];
|
||
+
|
||
+ pic2_shorttocex(buf, n);
|
||
+ if (fwrite(buf, (size_t) 2, (size_t) 1, pi->fp) < 1)
|
||
+ pic2_error(pi, PIC2_WRITE);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+static int pic2_write_char(pi, c)
|
||
+struct pic2_info *pi;
|
||
+int c;
|
||
+{
|
||
+ if (fputc(c, pi->fp) == EOF)
|
||
+ pic2_error(pi, PIC2_WRITE);
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions access the bit stream.
|
||
+ * pic2_read_bits:
|
||
+ * reads the specified bits from the file.
|
||
+ * pic2_write_bits:
|
||
+ * writes the specified bits to the file.
|
||
+ * pic2_flush_bits:
|
||
+ * flushes bit buffer to the file.
|
||
+ */
|
||
+static unsigned long pic2_read_bits(pi, bits)
|
||
+struct pic2_info *pi;
|
||
+int bits;
|
||
+{
|
||
+ unsigned long r = 0;
|
||
+
|
||
+ while (bits > 0) {
|
||
+ while (pi->bs.rest > 0 && bits > 0) {
|
||
+ r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0);
|
||
+ pi->bs.cur <<= 1;
|
||
+ pi->bs.rest--;
|
||
+ bits--;
|
||
+ }
|
||
+ if (bits > 0) {
|
||
+ int c;
|
||
+ if ((c = fgetc(pi->fp)) == EOF)
|
||
+ pic2_file_error(pi, PIC2_CORRUPT);
|
||
+ pi->bs.cur = (byte) c;
|
||
+ pi->bs.rest = 8;
|
||
+ }
|
||
+ }
|
||
+ return r;
|
||
+}
|
||
+
|
||
+static void pic2_write_bits(pi, dat, bits)
|
||
+struct pic2_info *pi;
|
||
+unsigned long dat;
|
||
+int bits;
|
||
+{
|
||
+ unsigned long dat_mask = 1 << (bits - 1);
|
||
+
|
||
+ while (bits > 0) {
|
||
+ while (pi->bs.rest < 8 && bits > 0) {
|
||
+ pi->bs.cur <<= 1;
|
||
+ if (dat & dat_mask)
|
||
+ pi->bs.cur |= 1;
|
||
+ pi->bs.rest++;
|
||
+ bits--;
|
||
+ dat_mask >>= 1;
|
||
+ }
|
||
+ if (pi->bs.rest >= 8) {
|
||
+ if ((fputc((int) pi->bs.cur, pi->fp)) == EOF)
|
||
+ pic2_error(pi, PIC2_WRITE);
|
||
+ pi->bs.cur = 0;
|
||
+ pi->bs.rest = 0;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void pic2_flush_bits(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ if (pi->bs.rest < 8) {
|
||
+ pi->bs.cur <<= 8 - pi->bs.rest;
|
||
+ if (fputc((int) pi->bs.cur, pi->fp) == EOF)
|
||
+ pic2_error(pi, PIC2_WRITE);
|
||
+ pi->bs.cur = 0;
|
||
+ pi->bs.rest = 0;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions initialize or clean up structures.
|
||
+ * pic2_init_info:
|
||
+ * initializes a pic2_info structure.
|
||
+ * pic2_cleanup_pic2_info:
|
||
+ * cleans up a pic_info structure.
|
||
+ * pic2_cleanup_pinfo:
|
||
+ * cleans up a PICINFO structure.
|
||
+ */
|
||
+static void pic2_init_info(pi)
|
||
+struct pic2_info *pi;
|
||
+{
|
||
+ xvbzero((char *) pi, sizeof(struct pic2_info));
|
||
+ pi->header = pic2_new(sizeof(struct pic2_header), "pic2_init_info#1");
|
||
+ pi->block = pic2_new(sizeof(struct pic2_block), "pic2_init_info#2");
|
||
+}
|
||
+
|
||
+static void pic2_cleanup_pic2_info(pi, writing)
|
||
+struct pic2_info *pi;
|
||
+int writing;
|
||
+{
|
||
+ if (!writing && pi->fp)
|
||
+ fclose(pi->fp);
|
||
+ if (pi->header)
|
||
+ free(pi->header);
|
||
+ if (pi->block)
|
||
+ free(pi->block);
|
||
+ pi->fp = NULL;
|
||
+ pi->header = NULL;
|
||
+ pi->block = NULL;
|
||
+ pi->comment = NULL;
|
||
+}
|
||
+
|
||
+static void pic2_cleanup_pinfo(pinfo)
|
||
+PICINFO *pinfo;
|
||
+{
|
||
+ if (pinfo->pic){
|
||
+ free(pinfo->pic);
|
||
+ pinfo->pic = NULL;
|
||
+ }
|
||
+ if (pinfo->comment){
|
||
+ free(pinfo->comment);
|
||
+ pinfo->comment = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Error Handlers.
|
||
+ * pic2_memory_error:
|
||
+ * shows an error message and terminates.
|
||
+ * pic2_error:
|
||
+ * shows a non-file error message and jumps to the entry for errors.
|
||
+ * pic2_file_error:
|
||
+ * shows a file error message and jumps to the entry for errors.
|
||
+ */
|
||
+static void pic2_memory_error(scm, fn)
|
||
+char *scm, *fn;
|
||
+{
|
||
+ char buf[128];
|
||
+ sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn);
|
||
+ FatalError(buf);
|
||
+}
|
||
+
|
||
+static void pic2_error(pi, mn)
|
||
+struct pic2_info *pi;
|
||
+int mn;
|
||
+{
|
||
+ SetISTR(ISTR_WARNING, "%s", pic2_msgs[mn]);
|
||
+ longjmp(pi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void pic2_file_error(pi, mn)
|
||
+ struct pic2_info *pi;
|
||
+ int mn;
|
||
+{
|
||
+ if (feof(pi->fp))
|
||
+ SetISTR(ISTR_WARNING, "%s (end of file)", pic2_msgs[mn]);
|
||
+ else
|
||
+ SetISTR(ISTR_WARNING, "%s (%s)", pic2_msgs[mn], ERRSTR(errno));
|
||
+ longjmp(pi->jmp, 1);
|
||
+}
|
||
+
|
||
+static void pic2_show_pic2_info(pi)
|
||
+ struct pic2_info *pi;
|
||
+{
|
||
+ fprintf(stderr, "file size: %ld.\n", pi->fsize);
|
||
+ fprintf(stderr, "full image size: %dx%d\n", pi->x_max, pi->y_max);
|
||
+ fprintf(stderr, "number of palettes: %d\n", pi->n_pal);
|
||
+ fprintf(stderr, "depth of palettes: %d\n", pi->pal_bits);
|
||
+ fprintf(stderr, "current block position: %ld\n", pi->block_pos);
|
||
+ fprintf(stderr, "next block position: %ld\n\n", pi->next_pos);
|
||
+
|
||
+ fprintf(stderr, "header flag: %x\n", pi->header->flag);
|
||
+ fprintf(stderr, "header size: %ld\n", pi->header->size);
|
||
+ fprintf(stderr, "x_aspect: %d, y_aspect: %d\n",
|
||
+ pi->header->x_aspect, pi->header->y_aspect);
|
||
+ fprintf(stderr, "number of color bits: %d\n\n", pi->header->depth);
|
||
+
|
||
+ fprintf(stderr, "image block id: %s\n", pi->block->id);
|
||
+ fprintf(stderr, "image block size: %ld\n", pi->block->size);
|
||
+ fprintf(stderr, "block flag: %x\n", pi->block->flag);
|
||
+
|
||
+ fprintf(stderr, "block image size: %dx%d\n",
|
||
+ pi->block->x_wid, pi->block->y_wid);
|
||
+ fprintf(stderr, "x_offset: %d\n", pi->block->x_offset);
|
||
+ fprintf(stderr, "y_offset: %d\n", pi->block->y_offset);
|
||
+ fprintf(stderr, "opaque color: %lx\n\n", pi->block->opaque);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function is similar to strncpy.
|
||
+ * But this pads with whitespace after the null character.
|
||
+ */
|
||
+static char *pic2_strncpy(dest, src, n)
|
||
+char *dest, *src;
|
||
+size_t n;
|
||
+{
|
||
+ char *r;
|
||
+
|
||
+ r = dest;
|
||
+ while (n--)
|
||
+ if ((src != NULL) && (*src != '\r') && (*src != '\n') && *src)
|
||
+ *dest++ = *src++;
|
||
+ else
|
||
+ *dest++ = ' ';
|
||
+ return (r);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions create a memory block.
|
||
+ */
|
||
+static void *pic2_malloc(size, fn)
|
||
+size_t size;
|
||
+char *fn;
|
||
+{
|
||
+ void *p;
|
||
+
|
||
+ p = (void *) malloc(size);
|
||
+ if (p == NULL)
|
||
+ pic2_memory_error("malloc", fn);
|
||
+ return (p);
|
||
+}
|
||
+
|
||
+static void *pic2_new(size, fn)
|
||
+size_t size;
|
||
+char *fn;
|
||
+{
|
||
+ void *p;
|
||
+
|
||
+ p = (void *) pic2_malloc(size, fn);
|
||
+ xvbzero((char *) p, size);
|
||
+ return (p);
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+/**** Stuff for PIC2Dialog box ****/
|
||
+
|
||
+#define TWIDE 320
|
||
+#define THIGH 178
|
||
+#define T_NBUTTS 2
|
||
+#define T_BOK 0
|
||
+#define T_BCANC 1
|
||
+#define BUTTH 24
|
||
+
|
||
+static void drawTD PARM((int,int,int,int));
|
||
+static void clickTD PARM((int,int));
|
||
+static void doCmd PARM((int));
|
||
+static void writePIC2 PARM((void));
|
||
+
|
||
+/* local variables */
|
||
+static FILE *fp;
|
||
+static char *filename;
|
||
+static int colorType;
|
||
+static int append;
|
||
+static int x_offset;
|
||
+static int y_offset;
|
||
+static BUTT tbut[T_NBUTTS];
|
||
+static RBUTT *typeRB;
|
||
+static RBUTT *depthRB;
|
||
+
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+void CreatePIC2W()
|
||
+{
|
||
+ int y;
|
||
+
|
||
+ pic2W = CreateWindow("xv pic2", "XVpic2", NULL,
|
||
+ TWIDE, THIGH, infofg, infobg, 0);
|
||
+ if (!pic2W)
|
||
+ FatalError("can't create pic2 window!");
|
||
+
|
||
+ XSelectInput(theDisp, pic2W,
|
||
+ ExposureMask | ButtonPressMask | KeyPressMask);
|
||
+
|
||
+ BTCreate(&tbut[T_BOK], pic2W, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH,
|
||
+ "Ok", infofg, infobg, hicol, locol);
|
||
+
|
||
+ BTCreate(&tbut[T_BCANC], pic2W, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH,
|
||
+ "Cancel", infofg, infobg, hicol, locol);
|
||
+
|
||
+ y = 55;
|
||
+ typeRB = RBCreate(NULL, pic2W, 36, y, "P2SS",
|
||
+ infofg, infobg,hicol,locol);
|
||
+ RBCreate(typeRB, pic2W, 36, y+18, "P2SF",
|
||
+ infofg, infobg,hicol,locol);
|
||
+ RBCreate(typeRB, pic2W, 36, y+36, "P2BM",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ RBCreate(typeRB, pic2W, 36, y+54, "P2BI",
|
||
+ infofg, infobg, hicol, locol);
|
||
+
|
||
+ depthRB = RBCreate(NULL, pic2W, TWIDE/2-16, y, " 3bit",
|
||
+ infofg, infobg,hicol,locol);
|
||
+ RBCreate(depthRB, pic2W, TWIDE/2-16, y+18, " 6bit",
|
||
+ infofg, infobg,hicol,locol);
|
||
+ RBCreate(depthRB, pic2W, TWIDE/2-16, y+36, " 9bit",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ RBCreate(depthRB, pic2W, TWIDE/2-16, y+54, "12bit",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ RBCreate(depthRB, pic2W, TWIDE/4*3-16, y, "15bit",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+18, "18bit",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+36, "21bit",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+54, "24bit",
|
||
+ infofg, infobg, hicol, locol);
|
||
+
|
||
+ XMapSubwindows(theDisp, pic2W);
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+void PIC2Dialog(vis)
|
||
+int vis;
|
||
+{
|
||
+ if (vis) {
|
||
+ CenterMapWindow(pic2W, tbut[T_BOK].x + tbut[T_BOK].w/2,
|
||
+ tbut[T_BOK].y + tbut[T_BOK].h/2, TWIDE, THIGH);
|
||
+ }
|
||
+ else XUnmapWindow(theDisp, pic2W);
|
||
+ pic2Up = vis;
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+int PIC2CheckEvent(xev)
|
||
+XEvent *xev;
|
||
+{
|
||
+ /* check event to see if it's for one of our subwindows. If it is,
|
||
+ deal accordingly and return '1'. Otherwise, return '0'. */
|
||
+
|
||
+ int rv;
|
||
+ rv = 1;
|
||
+
|
||
+ if (!pic2Up)
|
||
+ return (0);
|
||
+
|
||
+ if (xev->type == Expose) {
|
||
+ int x,y,w,h;
|
||
+ XExposeEvent *e = (XExposeEvent *) xev;
|
||
+ x = e->x; y = e->y; w = e->width; h = e->height;
|
||
+
|
||
+ if (e->window == pic2W) drawTD(x, y, w, h);
|
||
+ else rv = 0;
|
||
+ }
|
||
+
|
||
+ else if (xev->type == ButtonPress) {
|
||
+ XButtonEvent *e = (XButtonEvent *) xev;
|
||
+ int x,y;
|
||
+ x = e->x; y = e->y;
|
||
+
|
||
+ if (e->button == Button1) {
|
||
+ if (e->window == pic2W) clickTD(x,y);
|
||
+ else rv = 0;
|
||
+ } /* button1 */
|
||
+ else rv = 0;
|
||
+ } /* button press */
|
||
+
|
||
+
|
||
+ else if (xev->type == KeyPress) {
|
||
+ XKeyEvent *e = (XKeyEvent *) xev;
|
||
+ char buf[128]; KeySym ks; XComposeStatus status;
|
||
+ int stlen;
|
||
+
|
||
+ stlen = XLookupString(e,buf,128,&ks,&status);
|
||
+ buf[stlen] = '\0';
|
||
+
|
||
+ if (e->window == pic2W) {
|
||
+ if (stlen) {
|
||
+ if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
|
||
+ FakeButtonPress(&tbut[T_BOK]);
|
||
+ }
|
||
+ else if (buf[0] == '\033') { /* ESC */
|
||
+ FakeButtonPress(&tbut[T_BCANC]);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else rv = 0;
|
||
+ }
|
||
+ else rv = 0;
|
||
+
|
||
+ if (rv == 0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
|
||
+ XBell(theDisp, 50);
|
||
+ rv = 1; /* eat it */
|
||
+ }
|
||
+
|
||
+ return (rv);
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+int PIC2SaveParams(fname, col)
|
||
+char *fname;
|
||
+int col;
|
||
+{
|
||
+ filename = fname;
|
||
+ colorType = col;
|
||
+
|
||
+ /* see if we can open the output file before proceeding */
|
||
+ fp = pic2_OpenOutFile(filename, &append);
|
||
+ if (!fp)
|
||
+ return (-1);
|
||
+
|
||
+ RBSetActive(typeRB,0,1);
|
||
+ RBSetActive(typeRB,1,1);
|
||
+ RBSetActive(typeRB,2,1);
|
||
+ RBSetActive(typeRB,3,1);
|
||
+ RBSelect(typeRB,0);
|
||
+
|
||
+
|
||
+ if (append) {
|
||
+ struct pic2_info pic2;
|
||
+
|
||
+ pic2_init_info(&pic2);
|
||
+ pic2.fp = fp;
|
||
+ pic2_read_header(&pic2);
|
||
+
|
||
+ RBSetActive(depthRB,0,0);
|
||
+ RBSetActive(depthRB,1,0);
|
||
+ RBSetActive(depthRB,2,0);
|
||
+ RBSetActive(depthRB,3,0);
|
||
+ RBSetActive(depthRB,4,0);
|
||
+ RBSetActive(depthRB,5,0);
|
||
+ RBSetActive(depthRB,6,0);
|
||
+ RBSetActive(depthRB,7,0);
|
||
+
|
||
+ switch (pic2.header->depth) {
|
||
+ case 3:
|
||
+ RBSetActive(depthRB,0,1);
|
||
+ RBSelect(depthRB,0);
|
||
+ RBSetActive(typeRB,3,0);
|
||
+ break;
|
||
+ case 6:
|
||
+ RBSetActive(depthRB,1,1);
|
||
+ RBSelect(depthRB,1);
|
||
+ RBSetActive(typeRB,3,0);
|
||
+ break;
|
||
+ case 9:
|
||
+ RBSetActive(depthRB,2,1);
|
||
+ RBSelect(depthRB,2);
|
||
+ break;
|
||
+ case 12:
|
||
+ RBSetActive(depthRB,3,1);
|
||
+ RBSelect(depthRB,3);
|
||
+ break;
|
||
+ case 15:
|
||
+ RBSetActive(depthRB,4,1);
|
||
+ RBSelect(depthRB,4);
|
||
+ break;
|
||
+ case 18:
|
||
+ RBSetActive(depthRB,5,1);
|
||
+ RBSelect(depthRB,5);
|
||
+ RBSetActive(typeRB,3,0);
|
||
+ break;
|
||
+ case 21:
|
||
+ RBSetActive(depthRB,6,1);
|
||
+ RBSelect(depthRB,6);
|
||
+ RBSetActive(typeRB,3,0);
|
||
+ break;
|
||
+ case 24:
|
||
+ RBSetActive(depthRB,7,1);
|
||
+ RBSelect(depthRB,7);
|
||
+ RBSetActive(typeRB,3,0);
|
||
+ break;
|
||
+ default: {
|
||
+ char str[512];
|
||
+ sprintf(str, "unsupported PIC2 file '%s'.", filename);
|
||
+ ErrPopUp(str, "\nBummer");
|
||
+ CloseOutFile(fp, filename, 0);
|
||
+ fp = OpenOutFile(fname);
|
||
+ if (!fp)
|
||
+ return (-1);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ pic2_seek_file(&pic2, 0, SEEK_SET);
|
||
+ pic2_cleanup_pic2_info(&pic2, 1);
|
||
+ } else {
|
||
+ RBSetActive(depthRB,0,1);
|
||
+ RBSetActive(depthRB,1,1);
|
||
+ RBSetActive(depthRB,2,1);
|
||
+ RBSetActive(depthRB,3,1);
|
||
+ RBSetActive(depthRB,4,1);
|
||
+ RBSetActive(depthRB,5,1);
|
||
+ RBSetActive(depthRB,6,1);
|
||
+ RBSetActive(depthRB,7,1);
|
||
+ RBSelect(depthRB,7);
|
||
+ RBSetActive(typeRB,3,0);
|
||
+ }
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+static void drawTD(x,y,w,h)
|
||
+int x,y,w,h;
|
||
+{
|
||
+ char *title = "Save PIC2 file...";
|
||
+ int i;
|
||
+ XRectangle xr;
|
||
+
|
||
+ xr.x = x; xr.y = y; xr.width = w; xr.height = h;
|
||
+ XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
|
||
+
|
||
+ XSetForeground(theDisp, theGC, infofg);
|
||
+ XSetBackground(theDisp, theGC, infobg);
|
||
+
|
||
+ for (i = 0; i < T_NBUTTS; i++)
|
||
+ BTRedraw(&tbut[i]);
|
||
+
|
||
+ ULineString(pic2W, typeRB->x-16, typeRB->y-3-DESCENT, "FormatType");
|
||
+ ULineString(pic2W, depthRB->x-16, depthRB->y-3-DESCENT, "ColorDepth");
|
||
+ RBRedraw(typeRB, -1);
|
||
+ RBRedraw(depthRB, -1);
|
||
+
|
||
+ DrawString(pic2W, 20, 29, title);
|
||
+
|
||
+ XSetClipMask(theDisp, theGC, None);
|
||
+}
|
||
+
|
||
+static void clickTD(x,y)
|
||
+int x,y;
|
||
+{
|
||
+ int i;
|
||
+ BUTT *bp;
|
||
+
|
||
+ /* check BUTTs */
|
||
+
|
||
+ /* check the RBUTTS first, since they don't DO anything */
|
||
+ if ((i = RBClick(typeRB, x,y)) >= 0) {
|
||
+ (void) RBTrack(typeRB, i);
|
||
+ return;
|
||
+ } else if ((i = RBClick(depthRB, x,y)) >= 0) {
|
||
+ (void) RBTrack(depthRB, i);
|
||
+ if ((2 <= i) && (i <= 4))
|
||
+ RBSetActive(typeRB,3,1);
|
||
+ else {
|
||
+ RBSetActive(typeRB,3,0);
|
||
+ if (RBWhich(typeRB) == 3)
|
||
+ RBSelect(typeRB,0);
|
||
+ return;
|
||
+ }
|
||
+ }
|
||
+ for (i = 0; i < T_NBUTTS; i++) {
|
||
+ bp = &tbut[i];
|
||
+ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h))
|
||
+ break;
|
||
+ }
|
||
+ if (i < T_NBUTTS) /* found one */
|
||
+ if (BTTrack(bp))
|
||
+ doCmd(i);
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+/***************************************************/
|
||
+static void doCmd(cmd)
|
||
+int cmd;
|
||
+{
|
||
+ switch (cmd) {
|
||
+ case T_BOK: {
|
||
+ char *fullname;
|
||
+ char buf[64], *x_offsetp, *y_offsetp;
|
||
+ static const char *labels[] = { "\nOk", "\033Cancel" };
|
||
+ XEvent event;
|
||
+ int i;
|
||
+
|
||
+ strcpy(buf, "0,0");
|
||
+ i = GetStrPopUp("Enter offset (x,y):", labels, 2, buf, 64,
|
||
+ "01234567890,", 1);
|
||
+
|
||
+ if (i)
|
||
+ return;
|
||
+ if (strlen(buf)==0)
|
||
+ return;
|
||
+
|
||
+ x_offsetp = buf;
|
||
+ y_offsetp = index(buf, ',');
|
||
+ if (!y_offsetp)
|
||
+ return;
|
||
+ *(y_offsetp++) = '\0';
|
||
+ if ((*x_offsetp == '\0') || (*y_offsetp == '\0'))
|
||
+ return;
|
||
+ x_offset = atoi(x_offsetp);
|
||
+ y_offset = atoi(y_offsetp);
|
||
+
|
||
+ XNextEvent(theDisp, &event);
|
||
+ HandleEvent(&event, &i);
|
||
+
|
||
+ writePIC2();
|
||
+ PIC2Dialog(0);
|
||
+
|
||
+ fullname = GetDirFullName();
|
||
+ if (!ISPIPE(fullname[0])) {
|
||
+ XVCreatedFile(fullname);
|
||
+ StickInCtrlList(0);
|
||
+ }
|
||
+ }
|
||
+ break;
|
||
+ case T_BCANC:
|
||
+ pic2_KillNullFile(fp);
|
||
+ PIC2Dialog(0);
|
||
+ break;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static void writePIC2()
|
||
+{
|
||
+ int w, h, nc, rv, type, depth, ptype, pfree;
|
||
+ byte *inpix, *rmap, *gmap, *bmap;
|
||
+
|
||
+
|
||
+ WaitCursor();
|
||
+ inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
|
||
+
|
||
+ if (colorType == F_REDUCED)
|
||
+ colorType = F_FULLCOLOR;
|
||
+
|
||
+ switch (RBWhich(typeRB)) {
|
||
+ case 0: type = P2SS; break;
|
||
+ case 1: type = P2SF; break;
|
||
+ case 2: type = P2BM; break;
|
||
+ case 3: type = P2BI; break;
|
||
+ default: type = P2SS; break;
|
||
+ }
|
||
+ switch (RBWhich(depthRB)) {
|
||
+ case 0: depth = 3; break;
|
||
+ case 1: depth = 6; break;
|
||
+ case 2: depth = 9; break;
|
||
+ case 3: depth = 12; break;
|
||
+ case 4: depth = 15; break;
|
||
+ case 5: depth = 18; break;
|
||
+ case 6: depth = 21; break;
|
||
+ case 7: depth = 24; break;
|
||
+ default: depth = 24; break;
|
||
+ }
|
||
+ rv = WritePIC2(fp, inpix, ptype, w, h,
|
||
+ rmap, gmap, bmap, nc, colorType, filename,
|
||
+ type, depth, x_offset, y_offset, append, picComments);
|
||
+
|
||
+ if (CloseOutFile(fp, filename, rv) == 0)
|
||
+ DirBox(0);
|
||
+
|
||
+ if (pfree)
|
||
+ free(inpix);
|
||
+}
|
||
+#endif /* HAVE_PIC2 */
|
||
diff -u -r --new-file xv-3.10a.orig/xvpng.c xv-3.10a/xvpng.c
|
||
--- xv-3.10a.orig/xvpng.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvpng.c 2007-05-13 19:53:28.000000000 -0500
|
||
@@ -0,0 +1,1173 @@
|
||
+/*
|
||
+ * xvpng.c - load and write routines for 'PNG' format pictures
|
||
+ *
|
||
+ * callable functions
|
||
+ *
|
||
+ * CreatePNGW()
|
||
+ * PNGDialog(vis)
|
||
+ * PNGCheckEvent(xev)
|
||
+ * PNGSaveParams(fname, col)
|
||
+ * LoadPNG(fname, pinfo)
|
||
+ * VersionInfoPNG()
|
||
+ */
|
||
+
|
||
+/*#include "copyright.h"*/
|
||
+
|
||
+/* (c) 1995 by Alexander Lehmann <lehmann@mathematik.th-darmstadt.de>
|
||
+ * This file is a suplement to xv and is supplied under the same copying
|
||
+ * conditions (except the shareware part).
|
||
+ * The copyright will be passed on to JB at some future point if he
|
||
+ * so desires.
|
||
+ *
|
||
+ * Modified by Andreas Dilger <adilger@enel.ucalgary.ca> to fix
|
||
+ * error handling for bad PNGs, add dialogs for interlacing and
|
||
+ * compression selection, and upgrade to libpng-0.89.
|
||
+ *
|
||
+ * Modified by Greg Roelofs, TenThumbs and others to fix bugs and add
|
||
+ * features. See README.jumbo for details.
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+
|
||
+#ifdef HAVE_PNG
|
||
+
|
||
+#include "png.h"
|
||
+
|
||
+/*** Stuff for PNG Dialog box ***/
|
||
+#define PWIDE 318
|
||
+#define PHIGH 215
|
||
+
|
||
+#define DISPLAY_GAMMA 2.20 /* default display gamma */
|
||
+#define COMPRESSION 6 /* default zlib compression level, not max
|
||
+ (Z_BEST_COMPRESSION) */
|
||
+
|
||
+#define HAVE_tRNS (info_ptr->valid & PNG_INFO_tRNS)
|
||
+
|
||
+#define DWIDE 86
|
||
+#define DHIGH 104
|
||
+#define PFX (PWIDE-93)
|
||
+#define PFY 44
|
||
+#define PFH 20
|
||
+
|
||
+#define P_BOK 0
|
||
+#define P_BCANC 1
|
||
+#define P_NBUTTS 2
|
||
+
|
||
+#define BUTTH 24
|
||
+
|
||
+#define LF 10 /* a.k.a. '\n' on ASCII machines */
|
||
+#define CR 13 /* a.k.a. '\r' on ASCII machines */
|
||
+
|
||
+/*** local functions ***/
|
||
+static void drawPD PARM((int, int, int, int));
|
||
+static void clickPD PARM((int, int));
|
||
+static void doCmd PARM((int));
|
||
+static void writePNG PARM((void));
|
||
+static int WritePNG PARM((FILE *, byte *, int, int, int,
|
||
+ byte *, byte *, byte *, int));
|
||
+
|
||
+static void png_xv_error PARM((png_structp png_ptr,
|
||
+ png_const_charp message));
|
||
+static void png_xv_warning PARM((png_structp png_ptr,
|
||
+ png_const_charp message));
|
||
+
|
||
+/*** local variables ***/
|
||
+static char *filename;
|
||
+static const char *fbasename;
|
||
+static int colorType;
|
||
+static int read_anything;
|
||
+static double Display_Gamma = DISPLAY_GAMMA;
|
||
+
|
||
+static DIAL cDial, gDial;
|
||
+static BUTT pbut[P_NBUTTS];
|
||
+static CBUTT interCB;
|
||
+static CBUTT FdefCB, FnoneCB, FsubCB, FupCB, FavgCB, FPaethCB;
|
||
+
|
||
+
|
||
+#ifdef PNG_NO_STDIO
|
||
+/* NOTE: Some sites configure their version of the PNG Library without
|
||
+ * Standard I/O Library interfaces in order to avoid unnecessary inter-
|
||
+ * library dependencies at link time for applications that don't need Standard
|
||
+ * I/O. If your site is one of these, the following skeletal stubs, copied
|
||
+ * from libpng code, should be enough for this module. --Scott B. Marovich,
|
||
+ * Hewlett-Packard Laboratories, March 2001.
|
||
+ */
|
||
+static void
|
||
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||
+{
|
||
+
|
||
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
|
||
+ * instead of an int, which is what fread() actually returns.
|
||
+ */
|
||
+ if (fread(data,1,length,(FILE *)png_ptr->io_ptr) != length)
|
||
+ png_error(png_ptr, "Read Error");
|
||
+}
|
||
+
|
||
+static void
|
||
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||
+{
|
||
+ if (fwrite(data, 1, length, (FILE *)png_ptr->io_ptr) != length)
|
||
+ png_error(png_ptr, "Write Error");
|
||
+}
|
||
+#endif /* PNG_NO_STDIO */
|
||
+
|
||
+
|
||
+/**************************************************************************/
|
||
+/* PNG SAVE DIALOG ROUTINES ***********************************************/
|
||
+/**************************************************************************/
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+void CreatePNGW()
|
||
+{
|
||
+ pngW = CreateWindow("xv png", "XVPNG", NULL,
|
||
+ PWIDE, PHIGH, infofg, infobg, 0);
|
||
+ if (!pngW) FatalError("can't create PNG window!");
|
||
+
|
||
+ XSelectInput(theDisp, pngW, ExposureMask | ButtonPressMask | KeyPressMask);
|
||
+
|
||
+ DCreate(&cDial, pngW, 12, 25, DWIDE, DHIGH, (double)Z_NO_COMPRESSION,
|
||
+ (double)Z_BEST_COMPRESSION, COMPRESSION, 1.0, 3.0,
|
||
+ infofg, infobg, hicol, locol, "Compression", NULL);
|
||
+
|
||
+ DCreate(&gDial, pngW, DWIDE+27, 25, DWIDE, DHIGH, 1.0, 3.5,DISPLAY_GAMMA,0.01,0.2,
|
||
+ infofg, infobg, hicol, locol, "Disp. Gamma", NULL);
|
||
+
|
||
+ CBCreate(&interCB, pngW, DWIDE+30, DHIGH+3*LINEHIGH+2, "interlace",
|
||
+ infofg, infobg, hicol, locol);
|
||
+
|
||
+ CBCreate(&FdefCB, pngW, PFX, PFY, "Default",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ FdefCB.val = 1;
|
||
+
|
||
+ CBCreate(&FnoneCB, pngW, PFX, FdefCB.y + PFH + 4, "none",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ CBCreate(&FsubCB, pngW, PFX, FnoneCB.y + PFH, "sub",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ CBCreate(&FupCB, pngW, PFX, FsubCB.y + PFH, "up",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ CBCreate(&FavgCB, pngW, PFX, FupCB.y + PFH, "average",
|
||
+ infofg, infobg, hicol, locol);
|
||
+ CBCreate(&FPaethCB, pngW, PFX, FavgCB.y + PFH, "Paeth",
|
||
+ infofg, infobg, hicol, locol);
|
||
+
|
||
+ FnoneCB.val = FsubCB.val = FupCB.val = FavgCB.val = FPaethCB.val = 1;
|
||
+ CBSetActive(&FnoneCB, !FdefCB.val);
|
||
+ CBSetActive(&FsubCB, !FdefCB.val);
|
||
+ CBSetActive(&FupCB, !FdefCB.val);
|
||
+ CBSetActive(&FavgCB, !FdefCB.val);
|
||
+ CBSetActive(&FPaethCB, !FdefCB.val);
|
||
+
|
||
+ BTCreate(&pbut[P_BOK], pngW, PWIDE-180-1, PHIGH-10-BUTTH-1, 80, BUTTH,
|
||
+ "Ok", infofg, infobg, hicol, locol);
|
||
+ BTCreate(&pbut[P_BCANC], pngW, PWIDE-90-1, PHIGH-10-BUTTH-1, 80, BUTTH,
|
||
+ "Cancel", infofg, infobg, hicol, locol);
|
||
+
|
||
+ XMapSubwindows(theDisp, pngW);
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+void PNGDialog(vis)
|
||
+ int vis;
|
||
+{
|
||
+ if (vis) {
|
||
+ CenterMapWindow(pngW, pbut[P_BOK].x + (int) pbut[P_BOK].w/2,
|
||
+ pbut[P_BOK].y + (int) pbut[P_BOK].h/2,
|
||
+ PWIDE, PHIGH);
|
||
+ }
|
||
+ else XUnmapWindow(theDisp, pngW);
|
||
+ pngUp = vis;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+int PNGCheckEvent(xev)
|
||
+ XEvent *xev;
|
||
+{
|
||
+ /* check event to see if it's for one of our subwindows. If it is,
|
||
+ deal accordingly, and return '1'. Otherwise, return '0' */
|
||
+
|
||
+ int rv;
|
||
+ rv = 1;
|
||
+
|
||
+ if (!pngUp) return 0;
|
||
+
|
||
+ if (xev->type == Expose) {
|
||
+ int x,y,w,h;
|
||
+ XExposeEvent *e = (XExposeEvent *) xev;
|
||
+ x = e->x; y = e->y; w = e->width; h = e->height;
|
||
+
|
||
+ /* throw away excess expose events for 'dumb' windows */
|
||
+ if (e->count > 0 && (e->window == cDial.win)) {}
|
||
+
|
||
+ else if (e->window == pngW) drawPD(x, y, w, h);
|
||
+ else if (e->window == cDial.win) DRedraw(&cDial);
|
||
+ else if (e->window == gDial.win) DRedraw(&gDial);
|
||
+ else rv = 0;
|
||
+ }
|
||
+
|
||
+ else if (xev->type == ButtonPress) {
|
||
+ XButtonEvent *e = (XButtonEvent *) xev;
|
||
+ int x,y;
|
||
+ x = e->x; y = e->y;
|
||
+
|
||
+ if (e->button == Button1) {
|
||
+ if (e->window == pngW) clickPD(x,y);
|
||
+ else if (e->window == cDial.win) DTrack(&cDial,x,y);
|
||
+ else if (e->window == gDial.win) DTrack(&gDial,x,y);
|
||
+ else rv = 0;
|
||
+ } /* button1 */
|
||
+ else rv = 0;
|
||
+ } /* button press */
|
||
+
|
||
+ else if (xev->type == KeyPress) {
|
||
+ XKeyEvent *e = (XKeyEvent *) xev;
|
||
+ char buf[128]; KeySym ks;
|
||
+ int stlen;
|
||
+
|
||
+ stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL);
|
||
+ buf[stlen] = '\0';
|
||
+
|
||
+ RemapKeyCheck(ks, buf, &stlen);
|
||
+
|
||
+ if (e->window == pngW) {
|
||
+ if (stlen) {
|
||
+ if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
|
||
+ FakeButtonPress(&pbut[P_BOK]);
|
||
+ }
|
||
+ else if (buf[0] == '\033') { /* ESC */
|
||
+ FakeButtonPress(&pbut[P_BCANC]);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else rv = 0;
|
||
+ }
|
||
+ else rv = 0;
|
||
+
|
||
+ if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
|
||
+ XBell(theDisp, 50);
|
||
+ rv = 1; /* eat it */
|
||
+ }
|
||
+
|
||
+ return rv;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+void PNGSaveParams(fname, col)
|
||
+ char *fname;
|
||
+ int col;
|
||
+{
|
||
+ filename = fname;
|
||
+ colorType = col;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static void drawPD(x, y, w, h)
|
||
+ int x, y, w, h;
|
||
+{
|
||
+ const char *title = "Save PNG file...";
|
||
+
|
||
+ char ctitle1[20];
|
||
+ const char *ctitle2 = "Useful range";
|
||
+ const char *ctitle3 = "is 2 - 7.";
|
||
+ const char *ctitle4 = "Uncompressed = 0";
|
||
+
|
||
+ const char *ftitle = "Row Filters:";
|
||
+
|
||
+ char gtitle[20];
|
||
+
|
||
+ int i;
|
||
+ XRectangle xr;
|
||
+
|
||
+ xr.x = x; xr.y = y; xr.width = w; xr.height = h;
|
||
+ XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
|
||
+
|
||
+ XSetForeground(theDisp, theGC, infofg);
|
||
+ XSetBackground(theDisp, theGC, infobg);
|
||
+
|
||
+ for (i=0; i<P_NBUTTS; i++) BTRedraw(&pbut[i]);
|
||
+
|
||
+ DrawString(pngW, 15, 6+ASCENT, title);
|
||
+
|
||
+ sprintf(ctitle1, "Default = %d", COMPRESSION);
|
||
+ DrawString(pngW, 18, 6+DHIGH+cDial.y+ASCENT, ctitle1);
|
||
+ DrawString(pngW, 17, 6+DHIGH+cDial.y+ASCENT+LINEHIGH, ctitle2);
|
||
+ DrawString(pngW, 17, 6+DHIGH+cDial.y+ASCENT+2*LINEHIGH, ctitle3);
|
||
+ DrawString(pngW, 17, 6+DHIGH+cDial.y+ASCENT+3*LINEHIGH, ctitle4);
|
||
+
|
||
+ sprintf(gtitle, "Default = %g", DISPLAY_GAMMA);
|
||
+ DrawString(pngW, DWIDE+30, 6+DHIGH+gDial.y+ASCENT, gtitle);
|
||
+
|
||
+ ULineString(pngW, FdefCB.x, FdefCB.y-3-DESCENT, ftitle);
|
||
+ XDrawRectangle(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y-LINEHIGH-3,
|
||
+ 93, 8*LINEHIGH+15);
|
||
+ CBRedraw(&FdefCB);
|
||
+ XDrawLine(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y+LINEHIGH+4,
|
||
+ FdefCB.x+82, FdefCB.y+LINEHIGH+4);
|
||
+
|
||
+ CBRedraw(&FnoneCB);
|
||
+ CBRedraw(&FupCB);
|
||
+ CBRedraw(&FsubCB);
|
||
+ CBRedraw(&FavgCB);
|
||
+ CBRedraw(&FPaethCB);
|
||
+
|
||
+ CBRedraw(&interCB);
|
||
+
|
||
+ XSetClipMask(theDisp, theGC, None);
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static void clickPD(x,y)
|
||
+ int x,y;
|
||
+{
|
||
+ int i;
|
||
+ BUTT *bp;
|
||
+
|
||
+ /* check BUTTs */
|
||
+
|
||
+ for (i=0; i<P_NBUTTS; i++) {
|
||
+ bp = &pbut[i];
|
||
+ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
|
||
+ }
|
||
+
|
||
+ if (i<P_NBUTTS) { /* found one */
|
||
+ if (BTTrack(bp)) doCmd(i);
|
||
+ }
|
||
+
|
||
+ /* check CBUTTs */
|
||
+
|
||
+ else if (CBClick(&FdefCB,x,y)) {
|
||
+ int oldval = FdefCB.val;
|
||
+
|
||
+ CBTrack(&FdefCB);
|
||
+
|
||
+ if (oldval != FdefCB.val)
|
||
+ {
|
||
+ CBSetActive(&FnoneCB, !FdefCB.val);
|
||
+ CBSetActive(&FsubCB, !FdefCB.val);
|
||
+ CBSetActive(&FupCB, !FdefCB.val);
|
||
+ CBSetActive(&FavgCB, !FdefCB.val);
|
||
+ CBSetActive(&FPaethCB, !FdefCB.val);
|
||
+
|
||
+ CBRedraw(&FnoneCB);
|
||
+ CBRedraw(&FupCB);
|
||
+ CBRedraw(&FsubCB);
|
||
+ CBRedraw(&FavgCB);
|
||
+ CBRedraw(&FPaethCB);
|
||
+ }
|
||
+ }
|
||
+ else if (CBClick(&FnoneCB,x,y)) CBTrack(&FnoneCB);
|
||
+ else if (CBClick(&FsubCB,x,y)) CBTrack(&FsubCB);
|
||
+ else if (CBClick(&FupCB,x,y)) CBTrack(&FupCB);
|
||
+ else if (CBClick(&FavgCB,x,y)) CBTrack(&FavgCB);
|
||
+ else if (CBClick(&FPaethCB,x,y)) CBTrack(&FPaethCB);
|
||
+ else if (CBClick(&interCB,x,y)) CBTrack(&interCB);
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static void doCmd(cmd)
|
||
+ int cmd;
|
||
+{
|
||
+ switch (cmd) {
|
||
+ case P_BOK:
|
||
+ {
|
||
+ char *fullname;
|
||
+
|
||
+ writePNG();
|
||
+ PNGDialog(0);
|
||
+
|
||
+ fullname = GetDirFullName();
|
||
+ if (!ISPIPE(fullname[0])) {
|
||
+ XVCreatedFile(fullname);
|
||
+ StickInCtrlList(0);
|
||
+ }
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case P_BCANC:
|
||
+ PNGDialog(0);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static void writePNG()
|
||
+{
|
||
+ FILE *fp;
|
||
+ int w, h, nc, rv, ptype, pfree;
|
||
+ byte *inpix, *rmap, *gmap, *bmap;
|
||
+
|
||
+ fp = OpenOutFile(filename);
|
||
+ if (!fp) return;
|
||
+
|
||
+ fbasename = BaseName(filename);
|
||
+
|
||
+ WaitCursor();
|
||
+ inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
|
||
+
|
||
+ rv = WritePNG(fp, inpix, ptype, w, h, rmap, gmap, bmap, nc);
|
||
+
|
||
+ SetCursors(-1);
|
||
+
|
||
+ if (CloseOutFile(fp, filename, rv) == 0) DirBox(0);
|
||
+
|
||
+ if (pfree) free(inpix);
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols)
|
||
+ FILE *fp;
|
||
+ byte *pic;
|
||
+ int ptype, w, h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int numcols;
|
||
+ /* FIXME? what's diff between picComments and WriteGIF's comment arg? */
|
||
+{
|
||
+ png_struct *png_ptr;
|
||
+ png_info *info_ptr;
|
||
+ png_color palette[256];
|
||
+ png_textp text;
|
||
+ byte r1[256], g1[256], b1[256]; /* storage for deduped palette */
|
||
+ byte pc2nc[256]; /* for duplicated-color remapping (1st level) */
|
||
+ byte remap[256]; /* for bw/grayscale remapping (2nd level) */
|
||
+ int i, j, numuniqcols=0, filter, linesize, pass;
|
||
+ byte *p, *png_line;
|
||
+ char software[256];
|
||
+ char *savecmnt;
|
||
+
|
||
+ if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
|
||
+ png_xv_error, png_xv_warning)) == NULL) {
|
||
+ sprintf(software, "png_create_write_struct() failure in WritePNG");
|
||
+ FatalError(software);
|
||
+ }
|
||
+
|
||
+ if ((info_ptr = png_create_info_struct(png_ptr)) == NULL)
|
||
+ {
|
||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||
+ sprintf(software, "png_create_info_struct() failure in WritePNG");
|
||
+ FatalError(software);
|
||
+ }
|
||
+
|
||
+ if (setjmp(png_ptr->jmpbuf)) {
|
||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+#ifdef PNG_NO_STDIO
|
||
+ png_set_write_fn(png_ptr, fp, png_default_write_data, NULL);
|
||
+ png_set_error_fn(png_ptr, NULL, png_xv_error, png_xv_warning);
|
||
+#else
|
||
+ png_init_io(png_ptr, fp);
|
||
+#endif
|
||
+
|
||
+ png_set_compression_level(png_ptr, (int)cDial.val);
|
||
+
|
||
+ /* Don't bother filtering if we aren't compressing the image */
|
||
+ if (FdefCB.val)
|
||
+ {
|
||
+ if ((int)cDial.val == 0)
|
||
+ png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ filter = FnoneCB.val ? PNG_FILTER_NONE : 0;
|
||
+ filter |= FsubCB.val ? PNG_FILTER_SUB : 0;
|
||
+ filter |= FupCB.val ? PNG_FILTER_UP : 0;
|
||
+ filter |= FavgCB.val ? PNG_FILTER_AVG : 0;
|
||
+ filter |= FPaethCB.val ? PNG_FILTER_PAETH : 0;
|
||
+
|
||
+ png_set_filter(png_ptr, 0, filter);
|
||
+ }
|
||
+
|
||
+ info_ptr->width = w;
|
||
+ info_ptr->height = h;
|
||
+ if (w <= 0 || h <= 0) {
|
||
+ SetISTR(ISTR_WARNING, "%s: image dimensions out of range (%dx%d)",
|
||
+ fbasename, w, h);
|
||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ info_ptr->interlace_type = interCB.val ? 1 : 0;
|
||
+
|
||
+ linesize = 0; /* quiet a compiler warning */
|
||
+
|
||
+
|
||
+ /* GRR 20070331: remap palette to eliminate duplicated colors (as in
|
||
+ * xvgifwr.c) */
|
||
+ if (ptype == PIC8) {
|
||
+ for (i=0; i<256; ++i) {
|
||
+ pc2nc[i] = r1[i] = g1[i] = b1[i] = 0;
|
||
+ }
|
||
+
|
||
+ /* compute number of unique colors */
|
||
+ numuniqcols = 0;
|
||
+
|
||
+ for (i=0; i<numcols; ++i) {
|
||
+ /* see if color #i is already used */
|
||
+ for (j=0; j<i; ++j) {
|
||
+ if (rmap[i] == rmap[j] && gmap[i] == gmap[j] && bmap[i] == bmap[j])
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (j==i) { /* wasn't found */
|
||
+ pc2nc[i] = numuniqcols;
|
||
+ r1[numuniqcols] = rmap[i]; /* i.e., r1[pc2nc[i]] == rmap[i] */
|
||
+ g1[numuniqcols] = gmap[i];
|
||
+ b1[numuniqcols] = bmap[i];
|
||
+ ++numuniqcols;
|
||
+ }
|
||
+ else pc2nc[i] = pc2nc[j];
|
||
+ }
|
||
+ }
|
||
+
|
||
+
|
||
+ /* Appendix G.2 of user manual claims colorType will never be F_REDUCED... */
|
||
+ if (colorType == F_FULLCOLOR || colorType == F_REDUCED) {
|
||
+ if (ptype == PIC24) {
|
||
+ linesize = 3*w;
|
||
+ if (linesize/3 < w) {
|
||
+ SetISTR(ISTR_WARNING, "%s: image dimensions too large (%dx%d)",
|
||
+ fbasename, w, h);
|
||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||
+ return -1;
|
||
+ }
|
||
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB;
|
||
+ info_ptr->bit_depth = 8;
|
||
+ } else /* ptype == PIC8 */ {
|
||
+ linesize = w;
|
||
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
|
||
+ if (numuniqcols <= 2)
|
||
+ info_ptr->bit_depth = 1;
|
||
+ else
|
||
+ if (numuniqcols <= 4)
|
||
+ info_ptr->bit_depth = 2;
|
||
+ else
|
||
+ if (numuniqcols <= 16)
|
||
+ info_ptr->bit_depth = 4;
|
||
+ else
|
||
+ info_ptr->bit_depth = 8;
|
||
+
|
||
+ for (i = 0; i < numuniqcols; i++) {
|
||
+ palette[i].red = r1[i];
|
||
+ palette[i].green = g1[i];
|
||
+ palette[i].blue = b1[i];
|
||
+ }
|
||
+ info_ptr->num_palette = numuniqcols;
|
||
+ info_ptr->palette = palette;
|
||
+ info_ptr->valid |= PNG_INFO_PLTE;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ else if (colorType == F_GREYSCALE || colorType == F_BWDITHER) {
|
||
+ info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
|
||
+ if (colorType == F_BWDITHER) {
|
||
+ /* shouldn't happen */
|
||
+ if (ptype == PIC24) FatalError("PIC24 and B/W Stipple in WritePNG()");
|
||
+
|
||
+ info_ptr->bit_depth = 1;
|
||
+ if (MONO(r1[0], g1[0], b1[0]) > MONO(r1[1], g1[1], b1[1])) {
|
||
+ remap[0] = 1;
|
||
+ remap[1] = 0;
|
||
+ }
|
||
+ else {
|
||
+ remap[0] = 0;
|
||
+ remap[1] = 1;
|
||
+ }
|
||
+ linesize = w;
|
||
+ }
|
||
+ else /* F_GREYSCALE */ {
|
||
+ if (ptype == PIC24) {
|
||
+ linesize = 3*w;
|
||
+ if (linesize/3 < w) {
|
||
+ SetISTR(ISTR_WARNING, "%s: image dimensions too large (%dx%d)",
|
||
+ fbasename, w, h);
|
||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||
+ return -1;
|
||
+ }
|
||
+ info_ptr->bit_depth = 8;
|
||
+ }
|
||
+ else /* ptype == PIC8 */ {
|
||
+ int low_precision;
|
||
+
|
||
+ linesize = w;
|
||
+
|
||
+ /* NOTE: currently remap[] is the _secondary_ remapping of "palette"
|
||
+ * colors; its values are the final color/grayscale values, and,
|
||
+ * like r1/g1/b1[], it is _indexed_ by pc2nc[] (which is why its
|
||
+ * values come from r1/g1/b1[] and not from rmap/gmap/bmap[]).
|
||
+ *
|
||
+ * FIXME (probably): MONO() will create new duplicates; ideally should
|
||
+ * do extra round of dup-detection (and preferably collapse all
|
||
+ * remapping levels into single LUT). This stuff is a tad confusing.
|
||
+ */
|
||
+ for (i = 0; i < numuniqcols; i++)
|
||
+ remap[i] = MONO(r1[i], g1[i], b1[i]);
|
||
+
|
||
+ for (; i < 256; i++)
|
||
+ remap[i]=0; /* shouldn't be necessary, but... */
|
||
+
|
||
+ info_ptr->bit_depth = 8;
|
||
+
|
||
+ /* Note that this fails most of the time because of gamma */
|
||
+ /* (and that would be a bug: GRR FIXME) */
|
||
+ /* try to adjust to 4-bit precision grayscale */
|
||
+
|
||
+ low_precision=1;
|
||
+
|
||
+ for (i = 0; i < numuniqcols; i++) {
|
||
+ if ((remap[i] & 0x0f) * 0x11 != remap[i]) {
|
||
+ low_precision = 0;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (low_precision) {
|
||
+ for (i = 0; i < numuniqcols; i++) {
|
||
+ remap[i] &= 0xf;
|
||
+ }
|
||
+ info_ptr->bit_depth = 4;
|
||
+
|
||
+ /* try to adjust to 2-bit precision grayscale */
|
||
+
|
||
+ for (i = 0; i < numuniqcols; i++) {
|
||
+ if ((remap[i] & 0x03) * 0x05 != remap[i]) {
|
||
+ low_precision = 0;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (low_precision) {
|
||
+ for (i = 0; i < numuniqcols; i++) {
|
||
+ remap[i] &= 3;
|
||
+ }
|
||
+ info_ptr->bit_depth = 2;
|
||
+
|
||
+ /* try to adjust to 1-bit precision grayscale */
|
||
+
|
||
+ for (i = 0; i < numuniqcols; i++) {
|
||
+ if ((remap[i] & 0x01) * 0x03 != remap[i]) {
|
||
+ low_precision = 0;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (low_precision) {
|
||
+ for (i = 0; i < numuniqcols; i++) {
|
||
+ remap[i] &= 1;
|
||
+ }
|
||
+ info_ptr->bit_depth = 1;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ else
|
||
+ png_error(png_ptr, "Unknown colorstyle in WritePNG");
|
||
+
|
||
+ if ((text = (png_textp)malloc(sizeof(png_text)))) {
|
||
+ sprintf(software, "XV %s", REVDATE);
|
||
+
|
||
+ text->compression = -1;
|
||
+ text->key = "Software";
|
||
+ text->text = software;
|
||
+ text->text_length = strlen(text->text);
|
||
+
|
||
+ info_ptr->max_text = 1;
|
||
+ info_ptr->num_text = 1;
|
||
+ info_ptr->text = text;
|
||
+ }
|
||
+
|
||
+ Display_Gamma = gDial.val; /* Save the current gamma for loading */
|
||
+
|
||
+// GRR FIXME: add .Xdefaults option to omit writing gamma (size, cumulative errors when editing)--alternatively, modify save box to include "omit" checkbox
|
||
+ info_ptr->gamma = 1.0/gDial.val;
|
||
+ info_ptr->valid |= PNG_INFO_gAMA;
|
||
+
|
||
+ png_write_info(png_ptr, info_ptr);
|
||
+
|
||
+ if (info_ptr->bit_depth < 8)
|
||
+ png_set_packing(png_ptr);
|
||
+
|
||
+ pass=png_set_interlace_handling(png_ptr);
|
||
+
|
||
+ if ((png_line = malloc(linesize)) == NULL)
|
||
+ png_error(png_ptr, "cannot allocate temp image line");
|
||
+ /* FIXME: should be FatalError() */
|
||
+
|
||
+ for (i = 0; i < pass; ++i) {
|
||
+ int j;
|
||
+ p = pic;
|
||
+ for (j = 0; j < h; ++j) {
|
||
+ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) {
|
||
+ int k;
|
||
+ for (k = 0; k < w; ++k)
|
||
+ png_line[k] = ptype==PIC24 ? MONO(p[k*3], p[k*3+1], p[k*3+2]) :
|
||
+ remap[pc2nc[p[k]]];
|
||
+ png_write_row(png_ptr, png_line);
|
||
+ } else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
|
||
+ int k;
|
||
+ for (k = 0; k < w; ++k)
|
||
+ png_line[k] = pc2nc[p[k]];
|
||
+ png_write_row(png_ptr, png_line);
|
||
+ } else { /* PNG_COLOR_TYPE_RGB */
|
||
+ png_write_row(png_ptr, p);
|
||
+ }
|
||
+ if ((j & 0x1f) == 0) WaitCursor();
|
||
+ p += linesize;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ free(png_line);
|
||
+
|
||
+ savecmnt = NULL; /* quiet a compiler warning */
|
||
+
|
||
+ if (text) {
|
||
+ if (picComments && strlen(picComments) &&
|
||
+ (savecmnt = (char *)malloc((strlen(picComments) + 1)*sizeof(char)))) {
|
||
+ png_textp tp;
|
||
+ char *comment, *key;
|
||
+
|
||
+ strcpy(savecmnt, picComments);
|
||
+ key = savecmnt;
|
||
+ tp = text;
|
||
+ info_ptr->num_text = 0;
|
||
+
|
||
+ comment = strchr(key, ':');
|
||
+
|
||
+ do {
|
||
+ /* Allocate a larger structure for comments if necessary */
|
||
+ if (info_ptr->num_text >= info_ptr->max_text)
|
||
+ {
|
||
+ if ((tp =
|
||
+ realloc(text, (info_ptr->num_text + 2)*sizeof(png_text))) == NULL)
|
||
+ {
|
||
+ break;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ text = tp;
|
||
+ tp = &text[info_ptr->num_text];
|
||
+ info_ptr->max_text += 2;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* See if it looks like a PNG keyword from LoadPNG */
|
||
+ /* GRR: should test for strictly < 80, right? (key = 1-79 chars only) */
|
||
+ if (comment && comment[1] == ':' && comment - key <= 80) {
|
||
+ *(comment++) = '\0';
|
||
+ *(comment++) = '\0';
|
||
+
|
||
+ /* If the comment is the 'Software' chunk XV writes, we remove it,
|
||
+ since we have already stored one */
|
||
+ if (strcmp(key, "Software") == 0 && strncmp(comment, "XV", 2) == 0) {
|
||
+ key = strchr(comment, '\n');
|
||
+ if (key)
|
||
+ key++; /* skip \n */
|
||
+ comment = strchr(key, ':');
|
||
+ }
|
||
+ /* We have another keyword and/or comment to write out */
|
||
+ else {
|
||
+ tp->key = key;
|
||
+ tp->text = comment;
|
||
+
|
||
+ /* We have to find the end of this comment, and the next keyword
|
||
+ if there is one */
|
||
+ for (; NULL != (key = comment = strchr(comment, ':')); comment++)
|
||
+ if (key[1] == ':')
|
||
+ break;
|
||
+
|
||
+ /* It looks like another keyword, go backward to the beginning */
|
||
+ if (key) {
|
||
+ while (key > tp->text && *key != '\n')
|
||
+ key--;
|
||
+
|
||
+ if (key > tp->text && comment - key <= 80) {
|
||
+ *key = '\0';
|
||
+ key++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ tp->text_length = strlen(tp->text);
|
||
+
|
||
+ /* We don't have another keyword, so remove the last newline */
|
||
+ if (!key && tp->text[tp->text_length - 1] == '\n')
|
||
+ {
|
||
+ tp->text[tp->text_length] = '\0';
|
||
+ tp->text_length--;
|
||
+ }
|
||
+
|
||
+ tp->compression = tp->text_length > 640 ? 0 : -1;
|
||
+ info_ptr->num_text++;
|
||
+ tp++;
|
||
+ }
|
||
+ }
|
||
+ /* Just a generic comment: make sure line-endings are valid for PNG */
|
||
+ else {
|
||
+ char *p=key, *q=key; /* only deleting chars, not adding any */
|
||
+
|
||
+ while (*p) {
|
||
+ if (*p == CR) { /* lone CR or CR/LF: EOL either way */
|
||
+ *q++ = LF; /* LF is the only allowed PNG line-ending */
|
||
+ if (p[1] == LF) /* get rid of any original LF */
|
||
+ ++p;
|
||
+ } else if (*p == LF) /* lone LF */
|
||
+ *q++ = LF;
|
||
+ else
|
||
+ *q++ = *p;
|
||
+ ++p;
|
||
+ }
|
||
+ *q = '\0'; /* unnecessary...but what the heck */
|
||
+ tp->key = "Comment";
|
||
+ tp->text = key;
|
||
+ tp->text_length = q - key;
|
||
+ tp->compression = tp->text_length > 750 ? 0 : -1;
|
||
+ info_ptr->num_text++;
|
||
+ key = NULL;
|
||
+ }
|
||
+ } while (key && *key);
|
||
+ }
|
||
+ else {
|
||
+ info_ptr->num_text = 0;
|
||
+ }
|
||
+ }
|
||
+ info_ptr->text = text;
|
||
+
|
||
+ png_convert_from_time_t(&(info_ptr->mod_time), time(NULL));
|
||
+ info_ptr->valid |= PNG_INFO_tIME;
|
||
+
|
||
+ png_write_end(png_ptr, info_ptr);
|
||
+ fflush(fp); /* just in case we core-dump before finishing... */
|
||
+
|
||
+ if (text) {
|
||
+ free(text);
|
||
+ /* must do this or png_destroy_write_struct() 0.97+ will free text again: */
|
||
+ info_ptr->text = (png_textp)NULL;
|
||
+ if (savecmnt)
|
||
+ {
|
||
+ free(savecmnt);
|
||
+ savecmnt = (char *)NULL;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+int LoadPNG(fname, pinfo)
|
||
+ char *fname;
|
||
+ PICINFO *pinfo;
|
||
+/*******************************************/
|
||
+{
|
||
+ /* returns '1' on success */
|
||
+
|
||
+ FILE *fp;
|
||
+ png_struct *png_ptr;
|
||
+ png_info *info_ptr;
|
||
+ png_color_16 my_background;
|
||
+ int i,j;
|
||
+ int linesize, bufsize;
|
||
+ int filesize;
|
||
+ int pass;
|
||
+ int gray_to_rgb;
|
||
+ size_t commentsize;
|
||
+
|
||
+ fbasename = BaseName(fname);
|
||
+
|
||
+ pinfo->pic = (byte *) NULL;
|
||
+ pinfo->comment = (char *) NULL;
|
||
+
|
||
+ read_anything=0;
|
||
+
|
||
+ /* open the file */
|
||
+ fp = xv_fopen(fname,"r");
|
||
+ if (!fp) {
|
||
+ SetISTR(ISTR_WARNING,"%s: can't open file", fname);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* find the size of the file */
|
||
+ fseek(fp, 0L, 2);
|
||
+ filesize = ftell(fp);
|
||
+ fseek(fp, 0L, 0);
|
||
+
|
||
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
|
||
+ png_xv_error, png_xv_warning);
|
||
+ if (!png_ptr) {
|
||
+ fclose(fp);
|
||
+ FatalError("malloc failure in LoadPNG");
|
||
+ }
|
||
+
|
||
+ info_ptr = png_create_info_struct(png_ptr);
|
||
+
|
||
+ if (!info_ptr) {
|
||
+ fclose(fp);
|
||
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||
+ FatalError("malloc failure in LoadPNG");
|
||
+ }
|
||
+
|
||
+ if (setjmp(png_ptr->jmpbuf)) {
|
||
+ fclose(fp);
|
||
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||
+ if (!read_anything) {
|
||
+ if (pinfo->pic) {
|
||
+ free(pinfo->pic);
|
||
+ pinfo->pic = NULL;
|
||
+ }
|
||
+ if (pinfo->comment) {
|
||
+ free(pinfo->comment);
|
||
+ pinfo->comment = NULL;
|
||
+ }
|
||
+ }
|
||
+ return read_anything;
|
||
+ }
|
||
+
|
||
+#ifdef PNG_NO_STDIO
|
||
+ png_set_read_fn(png_ptr, fp, png_default_read_data);
|
||
+ png_set_error_fn(png_ptr, NULL, png_xv_error, png_xv_warning);
|
||
+#else
|
||
+ png_init_io(png_ptr, fp);
|
||
+#endif
|
||
+ png_read_info(png_ptr, info_ptr);
|
||
+
|
||
+ pinfo->w = pinfo->normw = info_ptr->width;
|
||
+ pinfo->h = pinfo->normh = info_ptr->height;
|
||
+ if (pinfo->w <= 0 || pinfo->h <= 0) {
|
||
+ SetISTR(ISTR_WARNING, "%s: image dimensions out of range (%dx%d)",
|
||
+ fbasename, pinfo->w, pinfo->h);
|
||
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||
+ return read_anything;
|
||
+ }
|
||
+
|
||
+ pinfo->frmType = F_PNG;
|
||
+
|
||
+ sprintf(pinfo->fullInfo, "PNG, %d bit ",
|
||
+ info_ptr->bit_depth * info_ptr->channels);
|
||
+
|
||
+ switch(info_ptr->color_type) {
|
||
+ case PNG_COLOR_TYPE_PALETTE:
|
||
+ strcat(pinfo->fullInfo, "palette color");
|
||
+ break;
|
||
+
|
||
+ case PNG_COLOR_TYPE_GRAY:
|
||
+ strcat(pinfo->fullInfo, "grayscale");
|
||
+ break;
|
||
+
|
||
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||
+ strcat(pinfo->fullInfo, "grayscale+alpha");
|
||
+ break;
|
||
+
|
||
+ case PNG_COLOR_TYPE_RGB:
|
||
+ strcat(pinfo->fullInfo, "truecolor");
|
||
+ break;
|
||
+
|
||
+ case PNG_COLOR_TYPE_RGB_ALPHA:
|
||
+ strcat(pinfo->fullInfo, "truecolor+alpha");
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ sprintf(pinfo->fullInfo + strlen(pinfo->fullInfo),
|
||
+ ", %sinterlaced. (%d bytes)",
|
||
+ info_ptr->interlace_type ? "" : "non-", filesize);
|
||
+
|
||
+ sprintf(pinfo->shrtInfo, "%lux%lu PNG", info_ptr->width, info_ptr->height);
|
||
+
|
||
+ if (info_ptr->bit_depth < 8)
|
||
+ png_set_packing(png_ptr);
|
||
+
|
||
+ if (info_ptr->valid & PNG_INFO_gAMA)
|
||
+ png_set_gamma(png_ptr, Display_Gamma, info_ptr->gamma);
|
||
+/*
|
||
+ *else
|
||
+ * png_set_gamma(png_ptr, Display_Gamma, 0.45);
|
||
+ */
|
||
+
|
||
+ gray_to_rgb = 0; /* quiet a compiler warning */
|
||
+
|
||
+ if (have_imagebg) {
|
||
+ if (info_ptr->bit_depth == 16) {
|
||
+ my_background.red = imagebgR;
|
||
+ my_background.green = imagebgG;
|
||
+ my_background.blue = imagebgB;
|
||
+ my_background.gray = imagebgG; /* used only if all three equal... */
|
||
+ } else {
|
||
+ my_background.red = (imagebgR >> 8);
|
||
+ my_background.green = (imagebgG >> 8);
|
||
+ my_background.blue = (imagebgB >> 8);
|
||
+ my_background.gray = my_background.green;
|
||
+ }
|
||
+ png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN,
|
||
+ 0, Display_Gamma);
|
||
+ if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
|
||
+ (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && HAVE_tRNS)) &&
|
||
+ (imagebgR != imagebgG || imagebgR != imagebgB)) /* i.e., colored bg */
|
||
+ {
|
||
+ png_set_gray_to_rgb(png_ptr);
|
||
+ png_set_expand(png_ptr);
|
||
+ gray_to_rgb = 1;
|
||
+ }
|
||
+ } else {
|
||
+ if (info_ptr->valid & PNG_INFO_bKGD) {
|
||
+ png_set_background(png_ptr, &info_ptr->background,
|
||
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
|
||
+ } else {
|
||
+ my_background.red = my_background.green = my_background.blue =
|
||
+ my_background.gray = 0;
|
||
+ png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN,
|
||
+ 0, Display_Gamma);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (info_ptr->bit_depth == 16)
|
||
+ png_set_strip_16(png_ptr);
|
||
+
|
||
+ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
|
||
+ info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||
+ {
|
||
+ if (info_ptr->bit_depth == 1)
|
||
+ pinfo->colType = F_BWDITHER;
|
||
+ else
|
||
+ pinfo->colType = F_GREYSCALE;
|
||
+ png_set_expand(png_ptr);
|
||
+ }
|
||
+
|
||
+ pass=png_set_interlace_handling(png_ptr);
|
||
+
|
||
+ png_read_update_info(png_ptr, info_ptr);
|
||
+
|
||
+ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
|
||
+ info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || gray_to_rgb)
|
||
+ {
|
||
+ linesize = 3 * pinfo->w;
|
||
+ if (linesize/3 < pinfo->w) { /* know pinfo->w > 0 (see above) */
|
||
+ SetISTR(ISTR_WARNING, "%s: image dimensions too large (%dx%d)",
|
||
+ fbasename, pinfo->w, pinfo->h);
|
||
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||
+ return read_anything;
|
||
+ }
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ pinfo->type = PIC24;
|
||
+ } else {
|
||
+ linesize = pinfo->w;
|
||
+ pinfo->type = PIC8;
|
||
+ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
|
||
+ info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||
+ for (i = 0; i < 256; i++)
|
||
+ pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
|
||
+ } else {
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ for (i = 0; i < info_ptr->num_palette; i++) {
|
||
+ pinfo->r[i] = info_ptr->palette[i].red;
|
||
+ pinfo->g[i] = info_ptr->palette[i].green;
|
||
+ pinfo->b[i] = info_ptr->palette[i].blue;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ bufsize = linesize * pinfo->h;
|
||
+ if (bufsize/linesize < pinfo->h) { /* know linesize, pinfo->h > 0 (above) */
|
||
+ SetISTR(ISTR_WARNING, "%s: image dimensions too large (%dx%d)",
|
||
+ fbasename, pinfo->w, pinfo->h);
|
||
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||
+ return read_anything;
|
||
+ }
|
||
+ pinfo->pic = calloc((size_t)bufsize, (size_t)1);
|
||
+
|
||
+ if (!pinfo->pic) {
|
||
+ png_error(png_ptr, "can't allocate space for PNG image");
|
||
+ }
|
||
+
|
||
+ png_start_read_image(png_ptr);
|
||
+
|
||
+ for (i = 0; i < pass; i++) {
|
||
+ byte *p = pinfo->pic;
|
||
+ for (j = 0; j < pinfo->h; j++) {
|
||
+ png_read_row(png_ptr, p, NULL);
|
||
+ read_anything = 1;
|
||
+ if ((j & 0x1f) == 0) WaitCursor();
|
||
+ p += linesize;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ png_read_end(png_ptr, info_ptr);
|
||
+
|
||
+ if (info_ptr->num_text > 0) {
|
||
+ commentsize = 1;
|
||
+
|
||
+ for (i = 0; i < info_ptr->num_text; i++)
|
||
+ commentsize += strlen(info_ptr->text[i].key) + 1 +
|
||
+ info_ptr->text[i].text_length + 2;
|
||
+
|
||
+ if ((pinfo->comment = malloc(commentsize)) == NULL) {
|
||
+ png_warning(png_ptr,"can't allocate comment string");
|
||
+ }
|
||
+ else {
|
||
+ pinfo->comment[0] = '\0';
|
||
+ for (i = 0; i < info_ptr->num_text; i++) {
|
||
+ strcat(pinfo->comment, info_ptr->text[i].key);
|
||
+ strcat(pinfo->comment, "::");
|
||
+ strcat(pinfo->comment, info_ptr->text[i].text);
|
||
+ strcat(pinfo->comment, "\n");
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||
+
|
||
+ fclose(fp);
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static void
|
||
+png_xv_error(png_ptr, message)
|
||
+ png_structp png_ptr;
|
||
+ png_const_charp message;
|
||
+{
|
||
+ SetISTR(ISTR_WARNING,"%s: libpng error: %s", fbasename, message);
|
||
+
|
||
+ longjmp(png_ptr->jmpbuf, 1);
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static void
|
||
+png_xv_warning(png_ptr, message)
|
||
+ png_structp png_ptr;
|
||
+ png_const_charp message;
|
||
+{
|
||
+ if (!png_ptr)
|
||
+ return;
|
||
+
|
||
+ SetISTR(ISTR_WARNING,"%s: libpng warning: %s", fbasename, message);
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+void
|
||
+VersionInfoPNG() /* GRR 19980605 */
|
||
+{
|
||
+ fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n",
|
||
+ PNG_LIBPNG_VER_STRING, png_libpng_ver);
|
||
+ fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n",
|
||
+ ZLIB_VERSION, zlib_version);
|
||
+}
|
||
+
|
||
+#endif /* HAVE_PNG */
|
||
diff -u -r --new-file xv-3.10a.orig/xvvd.c xv-3.10a/xvvd.c
|
||
--- xv-3.10a.orig/xvvd.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvvd.c 2007-04-15 23:30:19.000000000 -0500
|
||
@@ -0,0 +1,1101 @@
|
||
+
|
||
+/*
|
||
+ * xvvd.c - extract archived file automatically and regard it as a
|
||
+ * (virtual) directory.
|
||
+ */
|
||
+
|
||
+#define NEEDSDIR
|
||
+
|
||
+#include "xv.h"
|
||
+
|
||
+#ifdef AUTO_EXPAND
|
||
+
|
||
+static void vd_Dirtovd PARM((char *));
|
||
+static void vd_Vdtodir PARM((char *));
|
||
+static int vd_Mkvdir PARM((char *));
|
||
+static int vd_Rmvdir PARM((char *));
|
||
+static int vd_Movevdir PARM((char *, char *));
|
||
+static void vd_addvdtable PARM((char *));
|
||
+static void vd_packvdtable PARM((void));
|
||
+static int vd_recursive_mkdir PARM((char *));
|
||
+static int vd_recursive_rmdir PARM((char *));
|
||
+static void vd_optimize_path PARM((char *));
|
||
+static int vd_ftype PARM((char *));
|
||
+static int vd_compp PARM((char *, char *));
|
||
+static int vd_UncompressFile PARM((char *, char *));
|
||
+static int vd_tarc PARM((char *));
|
||
+static u_int vd_tar_sumchk PARM((char *));
|
||
+
|
||
+#define VD_VDTABLESIZE 100
|
||
+
|
||
+#define VD_ERR -2
|
||
+#define VD_UKN -1
|
||
+
|
||
+static char *ext_command[] = {
|
||
+/* KEEP 0 */
|
||
+ NULL,
|
||
+#define VD_ARC 1
|
||
+ "arc xo %s",
|
||
+#define VD_ARJ 2
|
||
+ "unarj x %s",
|
||
+#define VD_LZH 3
|
||
+ "lha -xf %s",
|
||
+#define VD_TAR 4
|
||
+ "tar xvf %s",
|
||
+#define VD_ZIP 5
|
||
+ "unzip -xo %s",
|
||
+#define VD_ZOO 6
|
||
+ "zoo xOS %s",
|
||
+};
|
||
+
|
||
+int vdcount = 0;
|
||
+
|
||
+static char vdroot[MAXPATHLEN+1];
|
||
+static char *vdtable[VD_VDTABLESIZE];
|
||
+
|
||
+/*
|
||
+ * These functions initialize and settle virtual directory system.
|
||
+ * Vdinit:
|
||
+ * creates root of virtual directory.
|
||
+ * Vdsettle:
|
||
+ * sweeps virtual directories.
|
||
+ */
|
||
+void Vdinit()
|
||
+{
|
||
+#ifndef VMS
|
||
+ char tmp[MAXPATHLEN+1];
|
||
+
|
||
+ xv_getwd(tmp, MAXPATHLEN+1);
|
||
+ if (chdir(tmpdir)) {
|
||
+ fprintf(stderr, "Warning: cannot chdir to tmpdir = '%s'.\n", tmpdir);
|
||
+ fprintf(stderr,
|
||
+ " I will use current directory '%s' instead of tmpdir.\n",
|
||
+ tmp);
|
||
+ }
|
||
+ xv_getwd(vdroot, MAXPATHLEN+1);
|
||
+ strcat(vdroot, "/.xvvdXXXXXX");
|
||
+ chdir(tmp);
|
||
+#else
|
||
+ sprintf(vdroot, "Sys$Scratch:xvvdXXXXXX");
|
||
+#endif /* VMS */
|
||
+#ifdef USE_MKSTEMP
|
||
+ close(mkstemp(vdroot));
|
||
+#else
|
||
+ mktemp(vdroot);
|
||
+#endif
|
||
+
|
||
+ if (!vd_recursive_mkdir(vdroot))
|
||
+ tmpdir = vdroot;
|
||
+}
|
||
+
|
||
+void Vdsettle()
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < vdcount; i++)
|
||
+ free(vdtable[i]);
|
||
+
|
||
+ vdcount = 0;
|
||
+
|
||
+ vd_recursive_rmdir(vdroot);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function chdir to virtual directory, if specified path is in
|
||
+ * virtual directlry.
|
||
+ */
|
||
+int Chvdir(dir)
|
||
+char *dir;
|
||
+{
|
||
+ char buf[MAXPATHLEN+1];
|
||
+
|
||
+ if (Mkvdir(dir) == VD_ERR)
|
||
+ return -1;
|
||
+
|
||
+ strcpy(buf, dir);
|
||
+ Dirtovd(buf);
|
||
+
|
||
+ return (chdir(buf));
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions convert directory <-> virtual directory.
|
||
+ * Dirtovd:
|
||
+ * front interface of vd_Dirtovd.
|
||
+ * vd_Dirtovd:
|
||
+ * converts directory to virtual directory.
|
||
+ * Vdtodir:
|
||
+ * front interface of vd_Vdtodir.
|
||
+ * vd_Vdtodir:
|
||
+ * converts virtual directory to normal directory.
|
||
+ * Dirtosubst:
|
||
+ * converts directory to substance of archive.
|
||
+ */
|
||
+void Dirtovd(dir)
|
||
+char *dir;
|
||
+{
|
||
+ vd_optimize_path(dir);
|
||
+
|
||
+ vd_Dirtovd(dir);
|
||
+}
|
||
+
|
||
+static void vd_Dirtovd(dir)
|
||
+char *dir;
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < vdcount; i++)
|
||
+ if (!strncmp(dir, vdtable[i], strlen(vdtable[i]))) {
|
||
+ char tmp[MAXPATHLEN+1];
|
||
+
|
||
+ sprintf(tmp, "%s%s", vdroot, dir);
|
||
+ strcpy(dir, tmp);
|
||
+ Dirtovd(dir);
|
||
+ }
|
||
+}
|
||
+
|
||
+void Vdtodir(dir)
|
||
+char *dir;
|
||
+{
|
||
+ vd_optimize_path(dir);
|
||
+
|
||
+ vd_Vdtodir(dir);
|
||
+}
|
||
+
|
||
+static void vd_Vdtodir(vd)
|
||
+char *vd;
|
||
+{
|
||
+ int i;
|
||
+ char tmp[MAXPATHLEN+1];
|
||
+
|
||
+ for (i = vdcount-1; i >= 0; i--) {
|
||
+ sprintf(tmp, "%s%s", vdroot, vdtable[i]);
|
||
+ if(!strncmp(vd, tmp, strlen(tmp))) {
|
||
+ strcpy(tmp, vd+strlen(vdroot));
|
||
+ strcpy(vd, tmp);
|
||
+ Vdtodir(vd);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+void Dirtosubst(dir)
|
||
+char *dir;
|
||
+{
|
||
+ char tmp[MAXPATHLEN+1];
|
||
+
|
||
+ Dirtovd(dir);
|
||
+
|
||
+ strcpy(tmp, dir+strlen(vdroot));
|
||
+
|
||
+ if (Isarchive(tmp))
|
||
+ strcpy(dir, tmp);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions make virtual directory and extracts archive, if
|
||
+ * specified path is archive.
|
||
+ * Mkvdir:
|
||
+ * front interface of vd_Mkvdir.
|
||
+ * vd_Mkvdir:
|
||
+ * does real work.
|
||
+ * Mkvdir_force: (used by makeThumbDir(in xvbrowse.c) only)
|
||
+ * make virtual directory by force.
|
||
+ */
|
||
+int Mkvdir(dir)
|
||
+char *dir;
|
||
+{
|
||
+ char dir1[MAXPATHLEN+1], dir2[MAXPATHLEN+1];
|
||
+ char *d1, *d2;
|
||
+ int rv;
|
||
+
|
||
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
|
||
+ sighold(SIGHUP);
|
||
+ sighold(SIGCHLD);
|
||
+#else
|
||
+ int mask;
|
||
+ mask = sigblock(sigmask(SIGHUP)|sigmask(SIGCHLD));
|
||
+#endif
|
||
+
|
||
+ strcpy(dir1, dir);
|
||
+ vd_optimize_path(dir1);
|
||
+
|
||
+ if ((rv = vd_Mkvdir(dir1)) != VD_ERR)
|
||
+ goto MKVDIR_END;
|
||
+
|
||
+ strcpy(dir2, dir1);
|
||
+ d2 = dir2 + strlen(dir2);
|
||
+ while (rv == VD_ERR) {
|
||
+ d2--;
|
||
+ while (*d2 != '/')
|
||
+ d2--;
|
||
+ *d2 = '\0';
|
||
+ rv = vd_Mkvdir(dir2);
|
||
+ }
|
||
+ d1 = dir1 + strlen(dir2);
|
||
+ while ((rv != VD_ERR) && (*d1 != '\0')) {
|
||
+ *d2++ = *d1++;
|
||
+ while ((*d1 != '/') && (*d1 != '\0'))
|
||
+ *d2++ = *d1++;
|
||
+ *d2 = '\0';
|
||
+ rv = vd_Mkvdir(dir2);
|
||
+ }
|
||
+
|
||
+MKVDIR_END:
|
||
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
|
||
+ sigrelse(SIGHUP);
|
||
+ sigrelse(SIGCHLD);
|
||
+#else
|
||
+ sigsetmask(mask);
|
||
+#endif
|
||
+
|
||
+ return rv;
|
||
+}
|
||
+
|
||
+static int vd_Mkvdir(dir)
|
||
+char *dir;
|
||
+{
|
||
+ char dir1[MAXPATHLEN+1], dir2[MAXPATHLEN+1], tmp[MAXPATHLEN+1];
|
||
+ int ftype, i;
|
||
+ struct stat st;
|
||
+ FILE *pfp;
|
||
+
|
||
+ strcpy(dir1, dir);
|
||
+ Dirtovd(dir1);
|
||
+ strcpy(dir2, dir1);
|
||
+
|
||
+ WaitCursor();
|
||
+
|
||
+ if ((ftype = vd_ftype(dir1)) < 0) {
|
||
+ SetCursors(-1);
|
||
+ return ftype;
|
||
+ }
|
||
+ if (ftype == RFT_COMPRESS) {
|
||
+ if (!(ftype = vd_compp(dir1, tmp))) {
|
||
+ SetCursors(-1);
|
||
+ return ftype;
|
||
+ }
|
||
+ strcpy(dir1, tmp);
|
||
+ }
|
||
+
|
||
+ if (!stat(dir1, &st)) {
|
||
+ for(i = 0; i < vdcount; i++)
|
||
+ if (!strcmp(vdtable[i], dir2)) {
|
||
+ SetCursors(-1);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (!S_ISDIR(st.st_mode)) {
|
||
+ char origdir[MAXPATHLEN+1], buf[MAXPATHLEN+10], buf1[100];
|
||
+
|
||
+ if (vdcount >= VD_VDTABLESIZE) {
|
||
+ ErrPopUp("Sorry, you can't make virtual directory any more.",
|
||
+ "\nBummer!");
|
||
+ goto VD_MKVDIR_ERR;
|
||
+ }
|
||
+
|
||
+ WaitCursor();
|
||
+
|
||
+ xv_getwd(origdir, MAXPATHLEN+1);
|
||
+
|
||
+ sprintf(tmp, "%s%s", vdroot, dir2);
|
||
+ if (vd_recursive_mkdir(tmp) || chdir(tmp)) {
|
||
+ SetISTR(ISTR_INFO, "fail to make virtual directory.");
|
||
+ Warning();
|
||
+ goto VD_MKVDIR_ERR;
|
||
+ }
|
||
+ sprintf(buf, ext_command[ftype], dir1);
|
||
+
|
||
+ WaitCursor();
|
||
+
|
||
+ if((pfp = popen(buf, "r")) == NULL) {
|
||
+ SetISTR(ISTR_INFO, "fail to extract archive '%s'.",
|
||
+ BaseName(dir2));
|
||
+ Warning();
|
||
+ goto VD_MKVDIR_ERR;
|
||
+ }
|
||
+ while (1) {
|
||
+ if (fread(buf1, 1, sizeof(buf1), pfp) < sizeof(buf1))
|
||
+ break;
|
||
+ WaitCursor();
|
||
+ }
|
||
+ if (!feof(pfp)) {
|
||
+ SetISTR(ISTR_INFO, "Pipe was broken.");
|
||
+ Warning();
|
||
+ pclose(pfp);
|
||
+ goto VD_MKVDIR_ERR;
|
||
+ }
|
||
+ pclose(pfp);
|
||
+
|
||
+ if (strcmp(dir1, dir2))
|
||
+ unlink(dir1);
|
||
+
|
||
+ vd_addvdtable(dir2);
|
||
+ Dirtovd(origdir);
|
||
+ chdir(origdir);
|
||
+ SetCursors(-1);
|
||
+ return 0;
|
||
+
|
||
+VD_MKVDIR_ERR:
|
||
+ if (strcmp(dir1, dir2))
|
||
+ unlink(dir1);
|
||
+ SetCursors(-1);
|
||
+ return VD_ERR;
|
||
+ }
|
||
+ }
|
||
+ SetCursors(-1);
|
||
+ return VD_ERR;
|
||
+}
|
||
+
|
||
+#ifdef VIRTUAL_TD
|
||
+void Mkvdir_force(dir)
|
||
+char *dir;
|
||
+{
|
||
+ char tmp[MAXPATHLEN+1];
|
||
+
|
||
+ if (vdcount >= VD_VDTABLESIZE) {
|
||
+ ErrPopUp("Sorry, you can't make virtual directory any more.",
|
||
+ "\nBummer!");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ sprintf(tmp, "%s%s", vdroot, dir);
|
||
+ if (vd_recursive_mkdir(tmp)) {
|
||
+ SetISTR(ISTR_INFO, "Failed to make virtual directory.");
|
||
+ Warning();
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ vd_addvdtable(dir);
|
||
+}
|
||
+#endif /* VIRTUAL_TD */
|
||
+
|
||
+/*
|
||
+ * These functions remove virtual directory, if exists.
|
||
+ * Rmvdir:
|
||
+ * front interface of vd_Rmvdir.
|
||
+ * vd_Rmvdir:
|
||
+ * remove virtual directory function.
|
||
+ */
|
||
+int Rmvdir(dir)
|
||
+char *dir;
|
||
+{
|
||
+ int rv;
|
||
+ char buf[MAXPATHLEN+1];
|
||
+
|
||
+ strcpy(buf, dir);
|
||
+ vd_optimize_path(buf);
|
||
+
|
||
+ rv = vd_Rmvdir(buf);
|
||
+ vd_packvdtable();
|
||
+ return rv;
|
||
+}
|
||
+
|
||
+static int vd_Rmvdir(dir)
|
||
+char *dir;
|
||
+{
|
||
+ int i;
|
||
+ char tmp[MAXPATHLEN+1];
|
||
+
|
||
+ for(i = 0; i < vdcount; i++)
|
||
+ if (!strncmp(dir, vdtable[i], strlen(dir))) {
|
||
+ sprintf(tmp, "%s%s", vdroot, vdtable[i]);
|
||
+ if (vd_Rmvdir(tmp))
|
||
+ return 1;
|
||
+ if (vd_recursive_rmdir(tmp))
|
||
+ return 1;
|
||
+ vdtable[i][0] = '\0';
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions move virtual directory, if exists.
|
||
+ * Movevdir:
|
||
+ * front interface of move virtual directory function.
|
||
+ * vd_Movevdir:
|
||
+ * does real work.
|
||
+ */
|
||
+int Movevdir(src, dst)
|
||
+char *src, *dst;
|
||
+{
|
||
+/*
|
||
+ char sbuf[MAXPATHLEN+1], dbuf[MAXPATHLEN+1];
|
||
+
|
||
+ strcpy(sbuf, src);
|
||
+ vd_optimize_path(sbuf);
|
||
+
|
||
+ strcpy(dbuf, dst);
|
||
+ vd_optimize_path(dbuf);
|
||
+
|
||
+ return (vd_Movevdir(sbuf, dbuf));
|
||
+*/
|
||
+ return (vd_Movevdir(src, dst));
|
||
+}
|
||
+
|
||
+static int vd_Movevdir(src, dst)
|
||
+char *src, *dst;
|
||
+{
|
||
+ int i;
|
||
+ char *p, *pp;
|
||
+ char tmp[MAXPATHLEN+1], tmps[MAXPATHLEN+1], tmpd[MAXPATHLEN+1];
|
||
+
|
||
+ for (i = 0; i < vdcount; i++)
|
||
+ if (!strncmp(src, vdtable[i], strlen(src))) {
|
||
+ sprintf(tmps, "%s%s", vdroot, vdtable[i]);
|
||
+ sprintf(tmp, "%s%s", dst, vdtable[i]+strlen(src));
|
||
+ sprintf(tmpd, "%s%s", vdroot, tmp);
|
||
+
|
||
+ if (vd_Movevdir(tmps, tmpd))
|
||
+ return 1;
|
||
+
|
||
+ pp = vdtable[i];
|
||
+ p = (char *) malloc(strlen(tmp)+1);
|
||
+ strcpy(p, tmp);
|
||
+ vdtable[i] = p;
|
||
+
|
||
+ strcpy(tmp, tmpd);
|
||
+ for (p = tmp+strlen(tmp); *p != '/'; p--)
|
||
+ ;
|
||
+ *p = '\0';
|
||
+
|
||
+ if (vd_recursive_mkdir(tmp))
|
||
+ goto VD_MOVEVDIR_ERR;
|
||
+
|
||
+ if (rename(tmps, tmpd) < 0)
|
||
+ goto VD_MOVEVDIR_ERR;
|
||
+
|
||
+ free(pp);
|
||
+ }
|
||
+ return 0;
|
||
+
|
||
+VD_MOVEVDIR_ERR:
|
||
+ free(vdtable[i]);
|
||
+ vdtable[i] = pp;
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions handle table of virtual directories.
|
||
+ * vd_addvdtable:
|
||
+ * adds virtual directory to table.
|
||
+ * vd_packvdtable:
|
||
+ * removes disused virtual directories from table.
|
||
+ */
|
||
+static void vd_addvdtable(vd)
|
||
+char *vd;
|
||
+{
|
||
+ char *p;
|
||
+ p = (char *) malloc(strlen(vd)+1);
|
||
+ strcpy(p, vd);
|
||
+ vdtable[vdcount] = p;
|
||
+ vdcount++;
|
||
+}
|
||
+
|
||
+static void vd_packvdtable()
|
||
+{
|
||
+ int i, j;
|
||
+
|
||
+ for (i = j = 0; i < vdcount; i++)
|
||
+ if (vdtable[i][0] != '\0')
|
||
+ vdtable[j++] = vdtable[i];
|
||
+ else
|
||
+ free(vdtable[i]);
|
||
+
|
||
+ vdcount = j;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These are utility functions.
|
||
+ * vd_recursive_mkdir:
|
||
+ * makes directories recursively.
|
||
+ * vd_recursive_rmdir
|
||
+ * removes directories recursively.
|
||
+ */
|
||
+static int vd_recursive_mkdir(dir)
|
||
+char *dir;
|
||
+{
|
||
+ char buf[MAXPATHLEN+1], *p;
|
||
+ struct stat st;
|
||
+
|
||
+ strcpy(buf, dir);
|
||
+
|
||
+ if (buf[strlen(buf) - 1] == '/')
|
||
+ buf[strlen(buf) - 1] = '\0';
|
||
+
|
||
+ p = rindex(buf, '/');
|
||
+ *p = '\0';
|
||
+
|
||
+ if (stat(buf, &st) < 0)
|
||
+ if (vd_recursive_mkdir(buf) < 0)
|
||
+ return (-1);
|
||
+
|
||
+ *p = '/';
|
||
+ if (mkdir(buf, 0700) < 0)
|
||
+ return (-1);
|
||
+
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+static int vd_recursive_rmdir(dir)
|
||
+char *dir;
|
||
+{
|
||
+ char buf[MAXPATHLEN+1], buf2[MAXPATHLEN+1];
|
||
+ DIR *dp;
|
||
+ struct dirent *di;
|
||
+
|
||
+ strcpy(buf, dir);
|
||
+
|
||
+ if (buf[strlen(buf) - 1] == '/')
|
||
+ buf[strlen(buf) - 1] = '\0';
|
||
+
|
||
+ if ((dp = opendir(buf)) == NULL)
|
||
+ return (-1);
|
||
+
|
||
+ while ((di = readdir(dp)) != NULL) {
|
||
+ struct stat st;
|
||
+
|
||
+ if (!strcmp(di->d_name, ".") || !strcmp(di->d_name, ".."))
|
||
+ continue;
|
||
+
|
||
+ sprintf(buf2, "%s/%s", dir, di->d_name);
|
||
+
|
||
+ stat(buf2, &st);
|
||
+ if (S_ISDIR(st.st_mode)) {
|
||
+ if (vd_recursive_rmdir(buf2) < 0)
|
||
+ goto VD_RECURSIVE_RMDIR_ERR;
|
||
+ } else
|
||
+ unlink(buf2);
|
||
+ }
|
||
+ if (rmdir(buf) < 0)
|
||
+ goto VD_RECURSIVE_RMDIR_ERR;
|
||
+
|
||
+ closedir(dp);
|
||
+ return (0);
|
||
+
|
||
+VD_RECURSIVE_RMDIR_ERR:
|
||
+ closedir(dp);
|
||
+ return (-1);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions test specified path.
|
||
+ * Isarchive:
|
||
+ * tests whether it's an archive?
|
||
+ * Isvdir:
|
||
+ * tests whether it's in the virtual directory?
|
||
+ */
|
||
+int Isarchive(path)
|
||
+char *path;
|
||
+{
|
||
+ int ftype;
|
||
+
|
||
+ if ((ftype = vd_ftype(path)) < 0)
|
||
+ return 0;
|
||
+
|
||
+ if (ftype == RFT_COMPRESS)
|
||
+ if (!(ftype = vd_compp(path, NULL)))
|
||
+ return 0;
|
||
+
|
||
+ return ftype;
|
||
+}
|
||
+
|
||
+int Isvdir(path)
|
||
+char *path;
|
||
+{
|
||
+ int rv = 0;
|
||
+ char tmp1[MAXPATHLEN+1], tmp2[MAXPATHLEN+1];
|
||
+ int archive1, archive2;
|
||
+
|
||
+ strcpy(tmp1, path);
|
||
+ strcpy(tmp2, path);
|
||
+
|
||
+ vd_optimize_path(tmp1);
|
||
+ Dirtovd(tmp2);
|
||
+
|
||
+ archive1 = Isarchive(tmp1);
|
||
+ archive2 = Isarchive(tmp2);
|
||
+
|
||
+ if (strcmp(tmp1, tmp2)) {
|
||
+ char tmp3[MAXPATHLEN+1], tmp4[MAXPATHLEN+1];
|
||
+ int archive3, archive4;
|
||
+
|
||
+ sprintf(tmp3, "%s%s", vdroot, tmp1);
|
||
+ strcpy(tmp4, tmp2+strlen(vdroot));
|
||
+
|
||
+ archive3 = Isarchive(tmp3);
|
||
+ archive4 = Isarchive(tmp4);
|
||
+
|
||
+ if (archive4 && !strcmp(tmp1, tmp4)) {
|
||
+ rv |= 06;
|
||
+ return rv;
|
||
+ }
|
||
+ rv |= 01;
|
||
+ if (archive2)
|
||
+ rv |= 02;
|
||
+ else if (archive4)
|
||
+ rv |= 06;
|
||
+ return rv;
|
||
+ }
|
||
+ if (archive1)
|
||
+ rv |= 02;
|
||
+
|
||
+ return rv;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function optimizes given path.
|
||
+ * Expand '~' to home directory and removes '.', and treat '..'.
|
||
+ */
|
||
+static void vd_optimize_path(path)
|
||
+char *path;
|
||
+{
|
||
+ char *tmp, *reserve;
|
||
+
|
||
+ if (!strcmp(path, STDINSTR))
|
||
+ return;
|
||
+
|
||
+ if (*path == '\0') {
|
||
+ xv_getwd(path, MAXPATHLEN+1);
|
||
+ return;
|
||
+ }
|
||
+ if (*path == '~')
|
||
+ Globify(path);
|
||
+ if (*path != '/') {
|
||
+ char tmp[MAXPATHLEN+1];
|
||
+
|
||
+ strcpy(tmp, path);
|
||
+ xv_getwd(path, MAXPATHLEN+1);
|
||
+ strcat(path, "/");
|
||
+ strcat(path, tmp);
|
||
+ }
|
||
+
|
||
+ reserve = tmp = path;
|
||
+ while(*path != '\0') {
|
||
+ if (*path == '/') {
|
||
+ *tmp++ = *path;
|
||
+ while (*++path == '/')
|
||
+ ;
|
||
+ continue;
|
||
+ }
|
||
+ if ((*path == '.') && (*(path-1) == '/')) {
|
||
+ if (*(path+1) == '/') {
|
||
+ tmp--;
|
||
+ path++;
|
||
+ continue;
|
||
+ } else if (*(path+1) == '\0') {
|
||
+ tmp--;
|
||
+ break;
|
||
+ } else if (*(path+1) == '.') {
|
||
+ if (*(path+2) == '/') {
|
||
+ if ((tmp - reserve) > 1)
|
||
+ for (tmp-=2; (*tmp != '/'); tmp--)
|
||
+ ;
|
||
+ else
|
||
+ tmp = reserve;
|
||
+ path+=2;
|
||
+ continue;
|
||
+ } else if (*(path+2) == '\0') {
|
||
+ if ((tmp - reserve) > 1)
|
||
+ for (tmp-=2; (*tmp != '/'); tmp--)
|
||
+ ;
|
||
+ else
|
||
+ tmp = reserve+1;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ *tmp++ = *path++;
|
||
+ }
|
||
+ if (((tmp - reserve) > 1) && *(tmp-1) == '/')
|
||
+ tmp--;
|
||
+ if (tmp == reserve)
|
||
+ *tmp++ = '/';
|
||
+
|
||
+ *tmp = '\0';
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions detect file type.
|
||
+ */
|
||
+static int vd_ftype(fname)
|
||
+char *fname;
|
||
+{
|
||
+ /* check archive type */
|
||
+
|
||
+ FILE *fp;
|
||
+ byte magicno[30]; /* first 30 bytes of file */
|
||
+ int rv, n;
|
||
+ struct stat st;
|
||
+
|
||
+ if (!fname) return VD_ERR; /* shouldn't happen */
|
||
+
|
||
+ if ((!stat(fname, &st)) && (st.st_mode & S_IFMT) == S_IFDIR)
|
||
+ return VD_UKN;
|
||
+ fp = xv_fopen(fname, "r");
|
||
+ if (!fp) return VD_ERR;
|
||
+
|
||
+ n = fread(magicno, (size_t) 1, (size_t) 30, fp);
|
||
+ fclose(fp);
|
||
+
|
||
+ if (n<30) return VD_UKN; /* files less than 30 bytes long... */
|
||
+
|
||
+ rv = VD_UKN;
|
||
+
|
||
+ if (magicno[0] == 0x60 && magicno[1]==0xea) rv = VD_ARJ;
|
||
+
|
||
+ else if (magicno[2] == '-' && magicno[3] == 'l' &&
|
||
+ magicno[4] == 'h') rv = VD_LZH;
|
||
+
|
||
+ else if (strncmp((char *) magicno,"PK", (size_t) 2)==0) rv = VD_ZIP;
|
||
+
|
||
+ else if (magicno[20]==0xdc && magicno[21]==0xa7 &&
|
||
+ magicno[22]==0xc4 && magicno[23]==0xfd) rv = VD_ZOO;
|
||
+
|
||
+ else if (vd_tarc(fname)) rv = VD_TAR;
|
||
+
|
||
+ else if (magicno[0]==0x1f && magicno[1]==0x9d) rv = RFT_COMPRESS;
|
||
+
|
||
+ else if (!strncmp((char *) &magicno[11], "MAJYO", (size_t) 5))
|
||
+ rv = VD_UKN; /* XXX */
|
||
+
|
||
+ else if (magicno[0] == 26) rv = VD_ARC;
|
||
+
|
||
+#ifdef GUNZIP
|
||
+ else if (magicno[0]==0x1f && magicno[1]==0x8b) rv = RFT_COMPRESS;/* gzip */
|
||
+ else if (magicno[0]==0x1f && magicno[1]==0x9e) rv = RFT_COMPRESS;/* old */
|
||
+ else if (magicno[0]==0x1f && magicno[1]==0x1e) rv = RFT_COMPRESS;/* pack */
|
||
+#endif
|
||
+
|
||
+ return rv;
|
||
+}
|
||
+
|
||
+static int vd_compp(path, newpath)
|
||
+char *path, *newpath;
|
||
+{
|
||
+ /*
|
||
+ * uncompress and check archive type.
|
||
+ *
|
||
+ * If newpath is NULL, uncompress only 512 byte of 'path' and
|
||
+ * check archive type, so it is for SPEED-UP strategy.
|
||
+ * In this case, caller this function does not have to unlink
|
||
+ * tempoary file.
|
||
+ * Unfortunately it does not work in VMS system.
|
||
+ */
|
||
+
|
||
+ int file_type, r;
|
||
+ char uncompname[128], basename[128];
|
||
+ int comptype;
|
||
+
|
||
+ if (newpath) *newpath = '\0';
|
||
+ strncpy(basename, path, 127);
|
||
+ comptype = ReadFileType(path);
|
||
+#if (defined(VMS) && !defined(GUNZIP))
|
||
+ /* VMS decompress doesn't like the file to have a trailing .Z in fname
|
||
+ however, GUnZip is OK with it, which we are calling UnCompress */
|
||
+ *rindex (basename, '.') = '\0';
|
||
+#endif
|
||
+#ifdef VMS
|
||
+ if (UncompressFile(basename, uncompname)) {
|
||
+#else
|
||
+ if (newpath == NULL)
|
||
+ r = vd_UncompressFile(basename, uncompname);
|
||
+ else
|
||
+ r = UncompressFile(basename, uncompname, comptype);
|
||
+ if (r) {
|
||
+#endif
|
||
+ if ((file_type = vd_ftype(uncompname)) < 0) {
|
||
+ unlink(uncompname);
|
||
+ return 0;
|
||
+ }
|
||
+ if (newpath) strcpy(newpath, uncompname);
|
||
+ else unlink(uncompname);
|
||
+ } else {
|
||
+ return 0;
|
||
+ }
|
||
+ return file_type;
|
||
+}
|
||
+
|
||
+#define HEADERSIZE 512
|
||
+
|
||
+static void vd_Dirtovd PARM((char *));
|
||
+static int stderr_on PARM((void));
|
||
+static int stderr_off PARM((void));
|
||
+static FILE *popen_nul PARM((char *, char *));
|
||
+
|
||
+static int vd_UncompressFile(name, uncompname)
|
||
+char *name, *uncompname;
|
||
+{
|
||
+ /* Yap, I`m nearly same as original `UncompnameFile' function, but,
|
||
+ 1) I extract `name' file ONLY first 512 byte.
|
||
+ 2) I'm called only from UNIX and UNIX like OS, *NOT* VMS */
|
||
+ /* returns '1' on success, with name of uncompressed file in uncompname
|
||
+ returns '0' on failure */
|
||
+
|
||
+ char namez[128], *fname, buf[512], tmp[HEADERSIZE];
|
||
+ int n, tmpfd;
|
||
+ FILE *pfp, *tfp;
|
||
+
|
||
+ fname = name;
|
||
+ namez[0] = '\0';
|
||
+
|
||
+
|
||
+#ifndef GUNZIP
|
||
+ /* see if compressed file name ends with '.Z'. If it *doesn't*, we need
|
||
+ to temporarily rename it so it *does*, uncompress it, and rename it
|
||
+ *back* to what it was. necessary because uncompress doesn't handle
|
||
+ files that don't end with '.Z' */
|
||
+
|
||
+ if (strlen(name) >= (size_t) 2 &&
|
||
+ strcmp(name + strlen(name)-2,".Z")!=0 &&
|
||
+ strcmp(name + strlen(name)-2,".z")!=0) {
|
||
+ strcpy(namez, name);
|
||
+ strcat(namez,".Z");
|
||
+
|
||
+ if (rename(name, namez) < 0) {
|
||
+ sprintf(buf, "Error renaming '%s' to '%s': %s",
|
||
+ name, namez, ERRSTR(errno));
|
||
+ ErrPopUp(buf, "\nBummer!");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ fname = namez;
|
||
+ }
|
||
+#endif /* not GUNZIP */
|
||
+
|
||
+ sprintf(uncompname, "%s/xvuXXXXXX", tmpdir);
|
||
+#ifdef USE_MKSTEMP
|
||
+ tmpfd = mkstemp(uncompname);
|
||
+#else
|
||
+ mktemp(uncompname);
|
||
+#endif
|
||
+
|
||
+ sprintf(buf,"%s -c %s", UNCOMPRESS, fname);
|
||
+ SetISTR(ISTR_INFO, "Uncompressing Header '%s'...", BaseName(fname));
|
||
+ if ((pfp = popen_nul(buf, "r")) == NULL) {
|
||
+ SetISTR(ISTR_INFO, "Cannot extract for archive '%s'.",
|
||
+ BaseName(fname));
|
||
+ Warning();
|
||
+#ifdef USE_MKSTEMP
|
||
+ if (tmpfd >= 0)
|
||
+ close(tmpfd);
|
||
+#endif
|
||
+ return 0;
|
||
+ }
|
||
+#ifdef USE_MKSTEMP
|
||
+ if (tmpfd < 0)
|
||
+#else
|
||
+ if ((tmpfd = open(uncompname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR)) < 0)
|
||
+#endif
|
||
+ {
|
||
+ SetISTR(ISTR_INFO, "Unable to create temporary file.",
|
||
+ BaseName(uncompname));
|
||
+ Warning();
|
||
+ pclose(pfp);
|
||
+ }
|
||
+ if ((tfp = fdopen(tmpfd, "w")) == NULL) {
|
||
+ SetISTR(ISTR_INFO, "Unable to create temporary file.",
|
||
+ BaseName(uncompname));
|
||
+ Warning();
|
||
+ close(tmpfd);
|
||
+ pclose(pfp);
|
||
+ return 0;
|
||
+ }
|
||
+ if ((n = fread(tmp, 1, sizeof(tmp), pfp)) != HEADERSIZE) {
|
||
+ SetISTR(ISTR_INFO, "Unable to read '%s'.",
|
||
+ BaseName(fname));
|
||
+ Warning();
|
||
+ pclose(pfp);
|
||
+ fflush(tfp);
|
||
+ fclose(tfp);
|
||
+ close(tmpfd);
|
||
+ return 0;
|
||
+ }
|
||
+ fwrite(tmp, 1, n, tfp);
|
||
+ fflush(tfp);
|
||
+ fclose(tfp);
|
||
+ close(tmpfd);
|
||
+ pclose(pfp);
|
||
+
|
||
+ /* if we renamed the file to end with a .Z for the sake of 'uncompress',
|
||
+ rename it back to what it once was... */
|
||
+
|
||
+ if (strlen(namez)) {
|
||
+ if (rename(namez, name) < 0) {
|
||
+ sprintf(buf, "Error renaming '%s' to '%s': %s",
|
||
+ namez, name, ERRSTR(errno));
|
||
+ ErrPopUp(buf, "\nBummer!");
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+#define TARBLOCK 512
|
||
+#define CKSTART 148 /* XXX */
|
||
+#define CKSIZE 8
|
||
+
|
||
+/*
|
||
+ * Tar file: 1, other: 0
|
||
+ */
|
||
+static int vd_tarc(fname)
|
||
+char *fname;
|
||
+{
|
||
+ FILE *fp;
|
||
+ unsigned int sum;
|
||
+ char *ckp, buf[TARBLOCK];
|
||
+
|
||
+ if ((fp = fopen(fname, "r")) == NULL)
|
||
+ return 0;
|
||
+
|
||
+ fread(buf, TARBLOCK, 1, fp);
|
||
+ fclose(fp);
|
||
+
|
||
+ for (sum = 0, ckp = buf + CKSTART;
|
||
+ (ckp < buf + CKSTART + CKSIZE) && *ckp != '\0';
|
||
+ ckp++) {
|
||
+ sum *= 8;
|
||
+ if (*ckp == ' ')
|
||
+ continue;
|
||
+ if (*ckp < '0' || '7' < *ckp)
|
||
+ return 0;
|
||
+ sum += *ckp - '0';
|
||
+ }
|
||
+ if (sum != vd_tar_sumchk(buf))
|
||
+ return 0;
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static unsigned int vd_tar_sumchk(buf)
|
||
+char *buf;
|
||
+{
|
||
+ int i;
|
||
+ unsigned int sum = 0;
|
||
+
|
||
+ for (i = 0; i < CKSTART; i++) {
|
||
+ sum += *(buf + i);
|
||
+ }
|
||
+ sum += ' ' * 8;
|
||
+ for (i += 8; i < TARBLOCK; i++) {
|
||
+ sum += *(buf + i);
|
||
+ }
|
||
+ return sum;
|
||
+}
|
||
+
|
||
+
|
||
+static int stde = -1; /* fd of stderr */
|
||
+static int nul = -1; /* fd of /dev/null */
|
||
+
|
||
+/*
|
||
+ * switch off the output to stderr(bypass to /dev/null).
|
||
+ */
|
||
+static int stderr_off()
|
||
+{
|
||
+ if (nul < 0)
|
||
+ nul = open("/dev/null", O_RDONLY);
|
||
+ if (nul < 0) {
|
||
+ fprintf(stderr, "/dev/null open failure\n");
|
||
+ return -1;
|
||
+ }
|
||
+ if (stde < 0)
|
||
+ stde = dup(2);
|
||
+ if (stde < 0) {
|
||
+ fprintf(stderr, "duplicate stderr failure\n");
|
||
+ return -1;
|
||
+ }
|
||
+ close(2);
|
||
+ dup(nul);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * turn on stderr output.
|
||
+ */
|
||
+static int stderr_on()
|
||
+{
|
||
+ if ((stde < 0) || (nul < 0)) {
|
||
+ fprintf(stderr, "stderr_on should call after stderr_off\n");
|
||
+ return -1;
|
||
+ }
|
||
+ close(2);
|
||
+ dup(stde);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * popen with no output to stderr.
|
||
+ */
|
||
+static FILE *popen_nul(prog, mode)
|
||
+char *prog, *mode;
|
||
+{
|
||
+ FILE *fp;
|
||
+
|
||
+ stderr_off();
|
||
+ fp = popen(prog, mode);
|
||
+ stderr_on();
|
||
+ return fp;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * These functions are for SIGNAL.
|
||
+ * If XV end by C-c, there are dust of directory which name is .xvvd???,
|
||
+ * made by xvvd. Then, I handle SIGINT, and add good finish.
|
||
+ */
|
||
+void vd_HUPhandler()
|
||
+{
|
||
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
|
||
+ sighold(SIGHUP);
|
||
+#else
|
||
+ int mask;
|
||
+ mask = sigblock(sigmask(SIGHUP));
|
||
+#endif
|
||
+
|
||
+ Vdsettle();
|
||
+
|
||
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
|
||
+ sigrelse(SIGHUP);
|
||
+ signal(SIGHUP, (void (*)PARM((int))) vd_HUPhandler);
|
||
+#else
|
||
+ sigsetmask(mask);
|
||
+#endif
|
||
+}
|
||
+
|
||
+void vd_handler(sig)
|
||
+int sig;
|
||
+{
|
||
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
|
||
+ sighold(sig);
|
||
+#else
|
||
+ sigblock(sigmask(sig));
|
||
+#endif
|
||
+
|
||
+ Quit(1); /*exit(1);*/
|
||
+}
|
||
+
|
||
+int vd_Xhandler(disp,event)
|
||
+Display *disp;
|
||
+XErrorEvent *event;
|
||
+{
|
||
+ Quit(1); /*exit(1);*/
|
||
+ return (1); /* Not reached */
|
||
+}
|
||
+
|
||
+int vd_XIOhandler(disp)
|
||
+Display *disp;
|
||
+{
|
||
+ fprintf(stderr, "XIO fatal IO error ? (?) on X server\n");
|
||
+ fprintf(stderr, "You must exit normally in xv usage.\n");
|
||
+ Quit(1); /*exit(1);*/
|
||
+ return (1); /* Not reached */
|
||
+}
|
||
+
|
||
+void vd_handler_setup()
|
||
+{
|
||
+ signal(SIGHUP, (void (*)PARM((int))) vd_HUPhandler);
|
||
+ signal(SIGINT, (void (*)PARM((int))) vd_handler);
|
||
+ signal(SIGTERM,(void (*)PARM((int))) vd_handler);
|
||
+
|
||
+ (void)XSetErrorHandler(vd_Xhandler);
|
||
+ (void)XSetIOErrorHandler(vd_XIOhandler);
|
||
+}
|
||
+#endif /* AUTO_EXPAND */
|
||
diff -u -r --new-file xv-3.10a.orig/xvwbmp.c xv-3.10a/xvwbmp.c
|
||
--- xv-3.10a.orig/xvwbmp.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvwbmp.c 2007-04-15 23:38:05.000000000 -0500
|
||
@@ -0,0 +1,345 @@
|
||
+/*
|
||
+ * xvwbmp.c - i/o routings for WBMP files
|
||
+ * defined by OMA (http://www.openmobilealliance.com)
|
||
+ * as a standard for images for micro devices.
|
||
+ *
|
||
+ * exports :
|
||
+ *
|
||
+ * LoadWBMP(fname, numcols);
|
||
+ * WriteWBMP(fp, pic, ptype, w, h, r, g, b, numcols, style);
|
||
+ *
|
||
+ * author: Pawel S. Veselov <vps@manticore.2y.net>
|
||
+ * http://manticore.2y.net/
|
||
+ *
|
||
+ */
|
||
+
|
||
+#include "xv.h"
|
||
+
|
||
+typedef short int16;
|
||
+typedef unsigned char uint8;
|
||
+typedef unsigned short uint16; /* sizeof (uint16) must == 2 */
|
||
+#if defined(__alpha) || _MIPS_SZLONG == 64
|
||
+typedef int int32;
|
||
+typedef unsigned int uint32; /* sizeof (uint32) must == 4 */
|
||
+#else
|
||
+typedef long int32;
|
||
+typedef unsigned long uint32; /* sizeof (uint32) must == 4 */
|
||
+#endif
|
||
+
|
||
+#define MUST(a) if (!(a)) {\
|
||
+ close(fd); \
|
||
+ return fail(st_fname, st_err); }
|
||
+#define READU8(fd,u) if ((read(fd, &u, 1)<1)) {\
|
||
+ myfree(); \
|
||
+ close(fd); \
|
||
+ return fail(st_fname, err_ueof); }
|
||
+#define SREADU8(fd, u) if ((read(fd, &u, 1,)<1)) {\
|
||
+ { st_err = err_ueof; return 0; }
|
||
+
|
||
+#define SREADC(fd, str, l) { \
|
||
+ str = (char*)mymalloc(l); \
|
||
+ if (!str) { \
|
||
+ myfree(); \
|
||
+ FatalError("LoadWBMP: can't malloc extension buffer"); \
|
||
+ } \
|
||
+ if (read(fd, str, l)<l) { \
|
||
+ st_err = err_ueof; \
|
||
+ return 0; \
|
||
+ }
|
||
+
|
||
+static const char err_ueof[] = "Unexpected EOF";
|
||
+static const char err_unst[] = "Unsupported image type";
|
||
+static const char err_extf[] = "Extensions are forbidden";
|
||
+static const char err_inmb[] = "Invalid multibyte integer";
|
||
+
|
||
+static const char *st_fname;
|
||
+static const char *st_err;
|
||
+
|
||
+static int fail PARM((const char *, const char *));
|
||
+static int read_mb PARM((int *, int));
|
||
+static void write_mb PARM((uint32, FILE *));
|
||
+static int read_ext PARM((int, uint8));
|
||
+static void *mymalloc PARM((int));
|
||
+static void myfree PARM((void));
|
||
+static uint8 *render1 PARM((uint8 *, int, int));
|
||
+
|
||
+static void **mymem = NULL;
|
||
+static int mymems = 0;
|
||
+
|
||
+
|
||
+int LoadWBMP(fname, pinfo)
|
||
+ char *fname;
|
||
+ PICINFO *pinfo;
|
||
+{
|
||
+ int fd;
|
||
+ int im_type; /* image type (only type 0 supported) */
|
||
+ uint8 fix_header; /* fixed header field */
|
||
+ int width, height;
|
||
+ int npixels, raw_size, aux;
|
||
+ uint8 * raw;
|
||
+
|
||
+ st_fname = fname;
|
||
+
|
||
+ fd = open(fname, O_RDONLY);
|
||
+ if (fd < 0) {
|
||
+ return fail(fname, "Couldn't open the file");
|
||
+ }
|
||
+
|
||
+ MUST(read_mb(&im_type, fd));
|
||
+ if (im_type) {
|
||
+ return fail(fname, err_unst);
|
||
+ }
|
||
+
|
||
+ READU8(fd, fix_header);
|
||
+
|
||
+ MUST(read_ext(fd, fix_header));
|
||
+
|
||
+ MUST(read_mb(&width, fd));
|
||
+ MUST(read_mb(&height, fd));
|
||
+
|
||
+ npixels = width * height;
|
||
+ raw_size = (npixels+7) / 8;
|
||
+ if (width <= 0 || height <= 0 || npixels/width != height ||
|
||
+ npixels+7 < npixels)
|
||
+ {
|
||
+ return fail(fname, "image dimensions out of range");
|
||
+ }
|
||
+
|
||
+ raw = mymalloc(raw_size);
|
||
+ if (!raw) {
|
||
+ myfree();
|
||
+ FatalError("LoadWBMP: can't malloc image buffer");
|
||
+ }
|
||
+
|
||
+ aux = read(fd, raw, raw_size);
|
||
+ if (aux < raw_size) {
|
||
+ fail(fname, "Image size shrank");
|
||
+ raw_size = aux;
|
||
+ }
|
||
+
|
||
+ pinfo->r[0] = 0;
|
||
+ pinfo->g[0] = 0;
|
||
+ pinfo->b[0] = 0;
|
||
+ pinfo->r[1] = 255;
|
||
+ pinfo->g[1] = 255;
|
||
+ pinfo->b[1] = 255;
|
||
+
|
||
+ pinfo->pic = render1(raw, raw_size, npixels);
|
||
+ pinfo->type = PIC8;
|
||
+
|
||
+ pinfo->w = pinfo->normw = width;
|
||
+ pinfo->h = pinfo->normh = height;
|
||
+ pinfo->frmType = F_BWDITHER;
|
||
+
|
||
+ sprintf(pinfo->fullInfo, "WBMP, 1 bit per pixel, %d bytes", raw_size);
|
||
+ sprintf(pinfo->shrtInfo, "%dx%d WBMP (WAP/OMA).", width, height);
|
||
+ pinfo->comment = (char*)NULL;
|
||
+
|
||
+ close(fd);
|
||
+
|
||
+ myfree();
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+
|
||
+int WriteWBMP(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle)
|
||
+ FILE *fp;
|
||
+ byte *pic;
|
||
+ int ptype, w, h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int numcols, colorstyle;
|
||
+{
|
||
+ int count = 0;
|
||
+ uint8 bit = 0;
|
||
+ int i;
|
||
+
|
||
+ write_mb(0, fp); /* type : always 0 */
|
||
+ putc(0, fp); /* fixed header : always 0 for type 0 */
|
||
+ write_mb((uint32)w, fp);
|
||
+ write_mb((uint32)h, fp);
|
||
+
|
||
+ /* ready to write data */
|
||
+
|
||
+ for (i=0; i<w*h; i++) {
|
||
+ bit |= (((pic[i]&1)<<(7-(count++))));
|
||
+ if (count == 8) {
|
||
+ putc(bit, fp);
|
||
+ count = 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (!count) {
|
||
+ putc(bit, fp);
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+static int fail(name, msg)
|
||
+ const char *name, *msg;
|
||
+{
|
||
+ SetISTR(ISTR_WARNING, "%s : %s", name, msg);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+static void write_mb(data, f)
|
||
+ uint32 data;
|
||
+ FILE *f;
|
||
+{
|
||
+ int i = 32;
|
||
+ uint32 aux = data;
|
||
+ int no;
|
||
+
|
||
+ if (!aux) {
|
||
+ i = 1;
|
||
+ } else {
|
||
+ while (!(aux & 0x80000000)) {
|
||
+ aux <<= 1;
|
||
+ i--;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* i tells us how many bits are left to encode */
|
||
+
|
||
+ no = (i / 7 + ((i % 7)?1:0))-1;
|
||
+
|
||
+ /*
|
||
+ fprintf(stderr, "writing %x, bits to write=%d, passes=%d\n",
|
||
+ data, i, no);
|
||
+ */
|
||
+
|
||
+ do {
|
||
+ uint8 value = no?0x80:0x0;
|
||
+ value |= ((data >> (no*7)) & 0x7f);
|
||
+ putc(value, f);
|
||
+ } while ((no--)>0);
|
||
+
|
||
+}
|
||
+
|
||
+
|
||
+static int read_mb(dst, fd)
|
||
+ int *dst, fd;
|
||
+{
|
||
+ int ac = 0;
|
||
+ int ct = 0;
|
||
+
|
||
+ while (1) {
|
||
+ uint8 bt;
|
||
+ if ((ct++)==6) {
|
||
+ st_err = err_inmb;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if ((read(fd, &bt, 1)) < 1) {
|
||
+ st_err = err_ueof;
|
||
+ return 0;
|
||
+ }
|
||
+ ac = (ac << 7) | (bt & 0x7f); /* accumulates up to 42 bits?? FIXME */
|
||
+ if (!(bt & 0x80))
|
||
+ break;
|
||
+ }
|
||
+ *dst = ac;
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+
|
||
+static int read_ext(fd, fixed)
|
||
+ int fd;
|
||
+ uint8 fixed;
|
||
+{
|
||
+ if (!(fixed&0x7f)) { /* no extensions */
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * The only described type is WBMP 0, that must not
|
||
+ * have extensions.
|
||
+ */
|
||
+
|
||
+ st_err = err_extf;
|
||
+ return 0;
|
||
+
|
||
+ /*
|
||
+
|
||
+ fixed = (fixed >> 5)&0x3;
|
||
+
|
||
+ switch (fixed) {
|
||
+ case 0:
|
||
+ while (true) {
|
||
+ SREADU8(fd, fixed);
|
||
+ if (!(fixed & 0x7f)) { break; }
|
||
+ }
|
||
+ break;
|
||
+ case 0x3:
|
||
+ {
|
||
+ char * par;
|
||
+ char * val;
|
||
+ SREADU8(fd, fixed);
|
||
+ SREADC(fd, par, (fixed>>4)&0x6);
|
||
+ SREADC(fd, val, fixed&0xf);
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+ */
|
||
+}
|
||
+
|
||
+
|
||
+static void *mymalloc(numbytes)
|
||
+ int numbytes;
|
||
+{
|
||
+ mymem = (void**)realloc(mymem, mymems+1);
|
||
+ if (!mymem)
|
||
+ FatalError("LoadWBMP: can't realloc buffer");
|
||
+ return (mymem[mymems++] = malloc(numbytes));
|
||
+}
|
||
+
|
||
+
|
||
+static void myfree()
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ if (mymem) {
|
||
+ for (i=0; i<mymems; i++) {
|
||
+ if (mymem[i])
|
||
+ free(mymem[i]);
|
||
+ }
|
||
+ free(mymem);
|
||
+ }
|
||
+ mymem = (void**)NULL;
|
||
+ mymems = 0;
|
||
+}
|
||
+
|
||
+
|
||
+static uint8 *render1(data, size, npixels)
|
||
+ uint8 *data;
|
||
+ int size, npixels;
|
||
+{
|
||
+ byte * pic;
|
||
+ int i;
|
||
+ int cnt = 0;
|
||
+ uint8 cb = *data;
|
||
+
|
||
+ pic = calloc(npixels,1); /* checked for overflow by caller */
|
||
+ if (!pic) {
|
||
+ myfree();
|
||
+ FatalError("LoadWBMP: can't allocate 'pic' buffer");
|
||
+ }
|
||
+
|
||
+ /* expand bits into bytes */
|
||
+ /* memset(pic, 0, npixels); */
|
||
+
|
||
+ for (i=0; i<npixels; i++) {
|
||
+
|
||
+ pic[i] = (cb>>7)&1;
|
||
+
|
||
+ if ((++cnt)==8) {
|
||
+ cb = *(++data);
|
||
+ cnt = 0;
|
||
+ } else {
|
||
+ cb <<=1;
|
||
+ }
|
||
+ }
|
||
+ return pic;
|
||
+}
|
||
diff -u -r --new-file xv-3.10a.orig/xvzx.c xv-3.10a/xvzx.c
|
||
--- xv-3.10a.orig/xvzx.c 1969-12-31 18:00:00.000000000 -0600
|
||
+++ xv-3.10a/xvzx.c 2007-05-13 19:53:46.000000000 -0500
|
||
@@ -0,0 +1,349 @@
|
||
+/*
|
||
+ * xvzx.c - load routine for Spectrum screen$
|
||
+ *
|
||
+ * John Elliott, 7 August 1998
|
||
+ *
|
||
+ * LoadZX(fname, pinfo) - load file
|
||
+ * WriteZX(fp,pic,ptype,w,h,r,g,b,numcols,style,cmt,comment) - convert to
|
||
+ * 256x192 SCREEN$ and save.
|
||
+ */
|
||
+
|
||
+#include "copyright.h"
|
||
+
|
||
+#include "xv.h"
|
||
+
|
||
+
|
||
+
|
||
+/*
|
||
+ * comments on error handling:
|
||
+ * a file with a bad header checksum is a warning error.
|
||
+ *
|
||
+ * not being able to malloc is a Fatal Error. The program is aborted.
|
||
+ */
|
||
+
|
||
+
|
||
+#define TRUNCSTR "File appears to be truncated."
|
||
+
|
||
+static int zxError PARM((const char *, const char *));
|
||
+
|
||
+static const char *bname;
|
||
+
|
||
+/*******************************************/
|
||
+int LoadZX(fname, pinfo)
|
||
+ char *fname;
|
||
+ PICINFO *pinfo;
|
||
+/*******************************************/
|
||
+{
|
||
+ /* returns '1' on success */
|
||
+
|
||
+ FILE *fp;
|
||
+ unsigned int c, c1;
|
||
+ int x,y, trunc;
|
||
+ byte *zxfile;
|
||
+
|
||
+ bname = BaseName(fname);
|
||
+
|
||
+ pinfo->pic = (byte *) NULL;
|
||
+ pinfo->comment = (char *) NULL;
|
||
+
|
||
+ /* Allocate memory for a 256x192x8bit image */
|
||
+
|
||
+ pinfo->pic = (byte *)malloc(256*192);
|
||
+ if (!pinfo->pic) FatalError("malloc failure in xvzx.c LoadZX");
|
||
+
|
||
+ /* Allocate 1B80h bytes and slurp the whole file into memory */
|
||
+
|
||
+ zxfile = (byte *)malloc(7040);
|
||
+ if (!zxfile) FatalError("malloc failure in xvzx.c LoadZX");
|
||
+
|
||
+ /* open the file */
|
||
+ fp = xv_fopen(fname,"r");
|
||
+ if (!fp) return (zxError(bname, "can't open file"));
|
||
+
|
||
+ /* Load it in en bloc */
|
||
+ memset(zxfile, 0, 7040);
|
||
+ if (fread(zxfile, 1, 7040, fp) < 7040) trunc = 1;
|
||
+
|
||
+ /* Transform to 8-bit */
|
||
+
|
||
+ for (y = 0; y < 192; y++) for (x = 0; x < 256; x++)
|
||
+ {
|
||
+ /* Spectrum screen layout: three 2k segments at y=0, y=64, y=128 */
|
||
+ /* In each segment: Scan lines 0,8,16,...,56,1,9,...,57 etc. Each
|
||
+ scanline is 32 bytes, so line 1 is 256 bytes after line 0
|
||
+
|
||
+ So address of line start is ((y>>6) * 2048) + ((y & 7) * 256)
|
||
+ + ((y & 0x38) * 4)
|
||
+
|
||
+ The colour byte for a cell is at screen + 6k + (y >> 3)*32 + (x>>3)
|
||
+
|
||
+ */
|
||
+
|
||
+ int offset;
|
||
+ byte *dst = pinfo->pic + 256*y + x;
|
||
+ byte attr, pt, mask;
|
||
+
|
||
+ offset = (y >> 6) * 2048;
|
||
+ offset += (y & 7) * 256;
|
||
+ offset += (y & 0x38) * 4;
|
||
+ offset += (x >> 3);
|
||
+
|
||
+ pt = zxfile[offset + 128]; /* Ink/paper map */
|
||
+
|
||
+ offset = 0x1880;
|
||
+ offset += (y >> 3) * 32;
|
||
+ offset += (x >> 3);
|
||
+
|
||
+ attr = zxfile[offset]; /* Colours for cell */
|
||
+
|
||
+ mask = 0x80;
|
||
+
|
||
+ if (x & 7) mask >>= (x & 7);
|
||
+
|
||
+ if (pt & mask) *dst = attr & 7; /* Ink */
|
||
+ else *dst = (attr >> 3) & 7; /* Paper */
|
||
+
|
||
+ if (attr & 0x40) *dst |= 8; /* High intensity */
|
||
+ }
|
||
+
|
||
+ /* Picture bytes converted; now build the colour maps */
|
||
+
|
||
+ pinfo->normw = pinfo->w = 256;
|
||
+ pinfo->normh = pinfo->h = 192;
|
||
+ pinfo->type = PIC8;
|
||
+
|
||
+ for (c = 0; c < 16; c++)
|
||
+ {
|
||
+ if (c < 8) c1 = 192; else c1 = 255; /* low-intensity colours use 192 */
|
||
+ /* high-intensity colours use 255 */
|
||
+ pinfo->b[c] = (c & 1 ? c1 : 0);
|
||
+ pinfo->r[c] = (c & 2 ? c1 : 0);
|
||
+ pinfo->g[c] = (c & 4 ? c1 : 0);
|
||
+ }
|
||
+
|
||
+ pinfo->colType = F_FULLCOLOR;
|
||
+ pinfo->frmType = F_ZX; /* Save as SCREEN$ */
|
||
+ sprintf(pinfo->fullInfo, "Spectrum SCREEN$, load address %04x",
|
||
+ zxfile[16]+256*zxfile[17]);
|
||
+ strcpy(pinfo->shrtInfo, "Spectrum SCREEN$.");
|
||
+
|
||
+ /* Almost as an afterthought, check that the +3DOS header is valid.
|
||
+
|
||
+ If it isn't, then odds are that the file isn't a graphic. But it
|
||
+ had the right magic number, so it might be. Let them see it anyway.
|
||
+
|
||
+ The check is: Byte 127 of the header should be the 8-bit sum of bytes
|
||
+ 0-126 of the header. The header should also have the
|
||
+ +3DOS magic number, but we know it does or we wouldn't
|
||
+ have got this far.
|
||
+ */
|
||
+
|
||
+ c1 = 0;
|
||
+ for (c1 = c = 0; c < 127; c++) c1 = ((c1 + zxfile[c]) & 0xFF);
|
||
+ if (c1 != zxfile[127]) zxError(bname, "Bad header checksum.");
|
||
+
|
||
+ fclose(fp);
|
||
+ free(zxfile);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+static int zxError(fname, st)
|
||
+ const char *fname, *st;
|
||
+{
|
||
+ SetISTR(ISTR_WARNING,"%s: %s", fname, st);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+/* Spectrum screen file header. The first 18 bytes are used in the magic
|
||
+ number test */
|
||
+
|
||
+byte ZXheader[128] =
|
||
+{
|
||
+ 'P', 'L', 'U', 'S', '3', 'D', 'O', 'S', 26, /* Spectrum +3DOS file */
|
||
+ 1, 0, /* Header type 1.0 */
|
||
+ 128, 27, 0, 0, /* 7040 bytes */
|
||
+ 3, /* Binary format */
|
||
+ 0, 27, /* 6912 data bytes */
|
||
+ 0, 64 /* load address 0x4000 */
|
||
+};
|
||
+
|
||
+
|
||
+
|
||
+/* Get the Spectrum colour/bright byte (0-15) from a pixel */
|
||
+
|
||
+static int PointZX(pic, w, h, rmap, gmap, bmap, x, y)
|
||
+ byte *pic;
|
||
+ int w,h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int x,y;
|
||
+{
|
||
+ int index, r, g, b, zxc;
|
||
+
|
||
+ /* If the picture is smaller than the screen, pad out the edges
|
||
+ with "bright black" - a colour not otherwise returned */
|
||
+
|
||
+ if (x >= w || y >= h) return 8;
|
||
+
|
||
+ /* Get colour index */
|
||
+
|
||
+ index = pic[y*w + x];
|
||
+
|
||
+ /* Convert to rgb */
|
||
+
|
||
+ r = rmap[index];
|
||
+ g = gmap[index];
|
||
+ b = bmap[index];
|
||
+ zxc = 0;
|
||
+
|
||
+ /* Work out Spectrum colour by a simplistic "nearest colour" method */
|
||
+
|
||
+ if (b >= 160) zxc |= 1; /* Blue */
|
||
+ if (r >= 160) zxc |= 2; /* Red */
|
||
+ if (g >= 160) zxc |= 4; /* Green */
|
||
+ if (r > 208 || g >= 208 || b >= 208) zxc |= 8; /* High intensity */
|
||
+
|
||
+ return zxc;
|
||
+}
|
||
+
|
||
+
|
||
+/* Work out what colours should be used in a cell */
|
||
+
|
||
+static void CellZX(pic, w, h, rmap, gmap, bmap, cx, cy, zxfile)
|
||
+ byte *pic;
|
||
+ int w,h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int cx,cy;
|
||
+ byte *zxfile;
|
||
+{
|
||
+ byte counts[16]; /* Count of no. of colours */
|
||
+ int offset, ink, paper, n, m, x, y, x0, y0, di, dp;
|
||
+
|
||
+ x0 = cx * 8; /* Convert from cell to pixel coords */
|
||
+ y0 = cy * 8;
|
||
+
|
||
+ for (n = 0; n < 16; n++) counts[n] = 0; /* Reset all counts */
|
||
+
|
||
+ /* Count no. of pixels of various colours */
|
||
+
|
||
+ for (y = y0; y < y0+8; y++) for (x = x0; x < x0+8; x++)
|
||
+ {
|
||
+ m = PointZX(pic, w, h, rmap, gmap, bmap, x, y);
|
||
+
|
||
+ counts[m]++;
|
||
+ }
|
||
+ counts[8] = 0; /* Discard Bright Black (pixels not in the picture area)
|
||
+ */
|
||
+
|
||
+ /* Assign the most popular colour as ink */
|
||
+ for (n = m = ink = 0; n < 16; n++) if (counts[n] > m)
|
||
+ {
|
||
+ ink = n;
|
||
+ m = counts[n];
|
||
+ }
|
||
+ counts[ink] = 0;
|
||
+
|
||
+ /* Assign the next most popular colour as paper */
|
||
+ for (n = m = paper = 0; n < 16; n++) if (counts[n] > m)
|
||
+ {
|
||
+ paper = n;
|
||
+ m = counts[n];
|
||
+ }
|
||
+ /* We have ink and paper. Set cell's attributes */
|
||
+
|
||
+ offset = cy*32 + cx + 0x1880;
|
||
+
|
||
+ /* Set the high-intensity bit if ink is high-intensity */
|
||
+ if (ink & 8) zxfile[offset] = 0x40; else zxfile[offset] = 0;
|
||
+ zxfile[offset] |= ((paper & 7) << 3);
|
||
+ zxfile[offset] |= (ink & 7);
|
||
+
|
||
+ /* Plot the points */
|
||
+ for (y = y0; y < y0+8; y++)
|
||
+ {
|
||
+ byte mask = 0x80;
|
||
+
|
||
+ offset = (y >> 6) * 2048;
|
||
+ offset += (y & 7) * 256;
|
||
+ offset += (y & 0x38) * 4;
|
||
+ offset += (x0 >> 3);
|
||
+
|
||
+ for (x = x0; x < x0+8; x++)
|
||
+ {
|
||
+ /* Work out whether the point should be plotted as ink or
|
||
+ paper */
|
||
+ m = PointZX(pic, w, h, rmap, gmap, bmap, x, y);
|
||
+
|
||
+ di = (ink & 7) - (m & 7); /* "Difference" from ink */
|
||
+ dp = (paper & 7) - (m & 7); /* "Difference" from paper */
|
||
+
|
||
+ if (di < 0) di = -di;
|
||
+ if (dp < 0) dp = -dp;
|
||
+
|
||
+ if (di < dp) /* Point is more like ink */
|
||
+ zxfile[offset+128] |= mask;
|
||
+
|
||
+ mask = (mask >> 1);
|
||
+ }
|
||
+ }
|
||
+
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+/*******************************************/
|
||
+int WriteZX(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,comment)
|
||
+ FILE *fp;
|
||
+ byte *pic;
|
||
+ int ptype, w,h;
|
||
+ byte *rmap, *gmap, *bmap;
|
||
+ int numcols, colorstyle;
|
||
+ char *comment;
|
||
+{
|
||
+ int rv, x, y;
|
||
+ byte *zxfile;
|
||
+ byte *pic8;
|
||
+ byte rtemp[256],gtemp[256],btemp[256];
|
||
+
|
||
+ /* To simplify matters, reduce 24-bit to 8-bit. Since the Spectrum
|
||
+ screen is 3.5-bit anyway, it doesn't make much difference */
|
||
+
|
||
+ if (ptype == PIC24)
|
||
+ {
|
||
+ pic8 = Conv24to8(pic, w, h, 256, rtemp,gtemp,btemp);
|
||
+ if (!pic8) FatalError("Unable to malloc in WriteZX()");
|
||
+ rmap = rtemp; gmap = gtemp; bmap = btemp; numcols=256;
|
||
+ }
|
||
+ else pic8 = pic;
|
||
+
|
||
+ ZXheader[127] = 0x71; /* The correct checksum. */
|
||
+
|
||
+ /* Create a memory image of the SCREEN$ */
|
||
+
|
||
+ zxfile = (byte *)malloc(7040);
|
||
+ if (!zxfile) FatalError("malloc failure in xvzx.c WriteZX");
|
||
+
|
||
+ memset(zxfile, 0, 7040); /* Reset all points to black */
|
||
+ memcpy(zxfile, ZXheader, 128); /* Create +3DOS header */
|
||
+
|
||
+ /* Convert the image, character cell by character cell */
|
||
+ for (y = 0; y < 24; y++) for (x = 0; x < 32; x++)
|
||
+ {
|
||
+ CellZX(pic8, w, h, rmap, gmap, bmap, x, y, zxfile);
|
||
+ }
|
||
+ rv = 0;
|
||
+ if (fwrite(zxfile, 1, 7040, fp) < 7040) rv = -1;
|
||
+
|
||
+ if (ptype == PIC24) free(pic8);
|
||
+ free(zxfile);
|
||
+
|
||
+ if (ferror(fp)) rv = -1;
|
||
+
|
||
+ return rv;
|
||
+}
|
||
+
|