14-Oct-94 20:33:53-GMT,156634;000000000001 Return-Path: joseph_skudlarek@MENTORG.COM Received: from newsgw.mentorg.com (newsgw.mentorg.com [137.202.128.5]) by CAMIS.Stanford.EDU (8.6.8.1/8.6.5) with ESMTP id NAA27665 for <macgifts@sumex-aim.stanford.edu>; Fri, 14 Oct 1994 13:33:36 -0700 Received: from wv.mentorg.com by newsgw.mentorg.com (8.6.4/CF5.22R) id QAA01403; Fri, 14 Oct 1994 16:32:25 -0400 Received: from em-wv03.mentorg.com by wv.mentorg.com (8.6.8.1/CF5.22R) id NAA15145; Fri, 14 Oct 1994 13:33:24 -0700 Received: from zigzag.MENTORG.COM by em-wv03.mentorg.com (8.6.8.1/CF5.19H) id NAA15768; Fri, 14 Oct 1994 13:33:17 -0700 From: joseph_skudlarek@MENTORG.COM (Joseph Skudlarek) Received: by zigzag.MENTORG.COM (1.38.193.4/CF3.4) id AA08296; Fri, 14 Oct 1994 13:33:14 -0700 Date: Fri, 14 Oct 1994 13:33:14 -0700 Message-Id: <9410142033.AA08296@zigzag.MENTORG.COM> To: macgifts@sumex-aim.stanford.edu Subject: mcvert-216.shar mcvert converts among Macintosh file formats used for file interchange, including BinHex 4.0 (.hqx) and MacBinary (.bin). mcvert is written in C and runs on many popular UNIX boxes. See mcvert.1/mcvert.man (the man page) for program details. See README for how to build mcvert. Please replace mcvert-215.shar with mcvert-216.shar, which follows. Major changes are described below. <<Changes>> * Internal * ----- * fix original bug of failing to convert lengths when extracting data * and resource forks from MacBinary files -- thanks to Thomas Lange * <tlange@namu01.gwdg.de> for finding and supplying the fix for this bug * tidy up for Alpha OSF1 -- thanks to Holger Debelts * <Debelts@rrz.Uni-Koeln.DE> for providing a fix for time()'s redeclaration * check <= 80 on *archive*, and avoid always rebuilding shar * due to unfulfilled check_linelen dependency * improve 2.15 comments * toss uninteresting lint messages <<shar>> #!/bin/sh # This is a shell archive (produced by shar 3.50) # To extract the files from this archive, save it to a file, remove # everything above the "!/bin/sh" line above, and type "sh file_name". # # made 10/14/1994 20:24 UTC by jskud@zigzag # Source directory /tmp_mnt/user/jskud/notes/mcvert # # existing files will NOT be overwritten unless -c is specified # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 45667 -r--r--r-- mcvert.c # 28332 -r--r--r-- hqxify.c # 6868 -r--r--r-- unpack.c # 9979 -r--r--r-- mactypes.h # 3030 -r--r--r-- Makefile # 1008 -r--r--r-- README # 7655 -r--r--r-- README-conversion # 13179 -r--r--r-- mcvert.idraw # 13789 -r--r--r-- mcvert.1 # 16929 -rw-r--r-- mcvert.man # # ============= mcvert.c ============== if test -f 'mcvert.c' -a X"$1" != X"-c"; then echo 'x - skipping mcvert.c (File already exists)' else echo 'x - extracting mcvert.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'mcvert.c' && /** X * mcvert.c - version 1.05 - 10 January, 1990 X * Written by Doug Moore - Rice University - dougm@rice.edu - April '87 X X * Sun bug fixes, assorted stuff - Jim Sasaki, March '89 X X * Changed default max_line_size from 2000 to unlimited - X * Doug Moore, April, '89 X X * Sun 3/60 doesn't like odd-sized structs. Bug fixed - Doug Moore, April, '89 X * - aided by Spencer W. Thomas X X * Didn't handle properly many hqx files combined in one file. Bug fixed - X * Doug Moore, June, '89 X X * Modified to handle MacBinaryII specification. Jim Van Verth, Sept, '89 X X * Fixed a bug when there are blank lines in hqx data, as happens when newline X * get translated to CRLF and then to \n\n, common for some file transfers. X * The last hqx line would be lost if the previous line was blank or junk. X * Glenn Trewitt, Stanford University, 1990 (1.05) X X * Fixed a bug that occurred when extracting data or resource X * forks on a Sun 4. It was a byte alignment problem. X * Rick Zaccone, zaccone@bucknell.edu. April 1991. Version 1.6 X X * Fixed: X * Sent all "Converting ... " lines to stdout instead of stderr X * Changed mactypes.h for HP-UX systems X * Alan Danziger, aland@cs.brandeis.edu. October 1991. Version 1.6.5 X X * ---------------------------------------------------------------------------- X * External X * ----- X * Fixed buffering bug when converting very small MacBinary files to hqx files. X * Provide helpful usage line. X * Control "Converting ... " lines separately with -S flag. X * Make encoding and decoding consistent by ignoring locked and init flags. X * Clean up some error messages; check for more errors; provide errno on error. X * Updated the man page. X * ----- X * Internal X * ----- X * Reformat source (sorry, local standard used by tools is tab space == 3) X * Remove compiler warning messages. X * Rename some variables. X * Added some comments to code. X * Added some offsets to struct definitions. X * Since the makefile has compilation flags, X * make the compiles depend on the Makefile. X * ----- X * Thanks to all who have gone before for creating, maintaining, X * improving, and providing this program and documentation. X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * {Jskud@std.mentorg.com,Joseph_Skudlarek@mentorg.com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 1.70 09Jul92 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * Added -V (Verbose) option (includes debugging information). X * Fixed bug converting hqx to MacBinary if last line is ":". X * Avoided a silent error and quick exit situation. X * ----- X * Internal X * ----- X * Got rid of almost all lint (SunOS and HP-UX) error messages. X * Compiled on SunOs, HP-UX, DomainOS. X * Incorporated Parag Patel <parag@netcom.com> changes for AU/X. X * Here's some diffs for really quick cheap hacks to get mcvert to compile X * and run under A/UX. The main problem was that timeb does not exist, so X * I added 2 #ifdef TIMEVAL to use the System-V timeval package instead. X * The Makefile just has a -DTIMEVAL and a magic -U_SYSV_SOURCE to get X * around a pre-defined type "ulong" in sys/types.h (thanks to Apple). X * Did more code overhauling: X * add lots more comments, rename variables, reformat source. X * Put code in un_hqx to avoid suspected buffering problem. X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 1.80 15Jul92 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * Made hqx file scan processing much smarter X * so, for example, info-mac/comm/qwk-reader.hqx, X * complete with extraneous colons in column one, converts correctly X * (problem described by Edward John Sabol <es2j+@andrew.cmu.edu>) X * Avoid silly perror on usage message (prompted by Edward John Sabol) X * Improve error message regarding improper format X * Added more caveats to man page X * ----- X * Internal X * ----- X * Fixed typo's in printf lines to pass all expected arguments X * (pointed out by Bo Holst-Christensen X * [holst@diku.dk/dikubhc1@uts.uni-c.dk/holst@login.dkuug.dk]) X * Tweak Makefile to ease shar creation and special case ulong, not A/UX X * Add yet more comments and debugging code X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 1.82 30Jul92 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * relax exactly 64 characters per incoming hqx file, and X * handle files without trailing newline, so, eg, X * Telnet2.5docs.sit.hqx now converts correctly X * (failure reported by Justin Sullivan <justin@f2.facts.uky.edu>) X * now also processes info-mac/app/road-map.hqx correctly X * (failure reported by Victor Norton<norton@andy.bgsu.edu>) X * rework the man page for improved clarity and completeness X * ----- X * Internal X * ----- X * avoid warning message from gcc on Sequent Balance mainframe X * reported by Justin Sullivan <justin@f2.facts.uky.edu> X * bump max incoming line length to 2048 from 255 X * add mcvert.ps target to Makefile X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 1.83 03Aug92 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * Found and fixed problem with byte ordering plaguing users of X * Sequent's Balance running DYNIX, and DEC computers. X * The error message looked something like X * hqx_to_bin_fork: writing nnn too many bytes X * Avoid generating debugging info if not to be printed -- cut runtime in half! X * Generalize and incorporate -I (info) option processing provided by X * Paul Franklin, Computer Enginnering, Univ. of Calif., Davis CA 95616 X * pdfranklin@ucdavis.edu. X * Added heuristic to avoid false matches in mail headers. X * problem expertly characterized, solution beta tested, and subsequent X * improvement suggested by "Jim (J.) Lattanzi" <lattanzi@bnr.ca> X * so segmented comp.binaries.mac files (either multi-file or concatenated X * single file) should now convert correctly. X * Added -H switch to disable heuristic. X * Document heuristic in man page. X * Fixed (long-standing) bug which precluded -p option from being recognized X * and verified decompressing and unpacking of PIT files working. X * Thanks to Dave Clemans for providing me with a version of PackIt. X * Add the version to the extened Usage message emitted by the program. X * Tune the syntax of the summary in the program and man page. X * Cleaned up spelling mistakes in the man page. X * ----- X * Internal X * ----- X * Close all open streams -- X * fix for binfile by Paul Franklin <pdfranklin@ucdavis.edu> X * Incorporate changes suggested by Barry_Wolman@transarc.com X * to mactypes.h and Makefile for support of IBM RS/6000 running AIX 3.2 X * reformat Makefile to avoid long option lines X * Identify the right Makefile lines for Irix too X * suggested by Jack Repenning (jackr@dblues.wpd.sgi.com) X * Clean up the stream handling and add mopen/mclose X * avoid unnecessary /dev/null opens X * all file open/close/read/write are checked for success X * Lower lint content on SunOS and HP-UX. X * avoiding all "sometimes ignored" lint messages. X * Improve modularity with mopen/mclose/converting routines. X * Tune debugging output information. X * Verify that passes smoke tests on DomainOS/SunOS/HP-UX/ULTRIX. X * Reformat these comments to avoid tabs. X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 1.87 25Sep92 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * Add README file which describes how to configure and compile mcvert X * Handle multiple BinHex4.0 inputs in a single file again (thanks to X * <Mark_Larimer@pigeon.cpg.cdc.com> for pointing out this regression) X * Emit the MacBinary header if verbose (to get create and modify times) X * ----- X * Internal X * ----- X * Rename some variables, create mac2unix (time) routine, more comments X * Keep lint content low X * Pull unnecessary include of <net/nh.h> -- avoid breaking AIX 3.1 X * Fix = vs == typo dealing with protect bit X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 1.88 08Dec92 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * emit input file names when verbose is enabled X * (suggested by franklin@eecs.ucdavis.edu) X * make it easier to build on AT&T 3B2's X * ----- X * Internal X * ----- X * provide compile time switch to avoid bzero and bcopy, and use memset X * and memcpy instead (pointed out by linger@drystone.attmail.com, and X * requested again by Larry S. Staples <attjp4!lss>) X * update Makefile to include incantations required for AT&T 3B2's X * fflush all diagnostic output to ensure correct order when output to a file X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 1.89 05Jan93 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * incorporate MAC_FILETYPE support provided by <root@genome.stanford.edu> X * minor edits to man page X * ----- X * Internal X * ----- X * update Makefile to simplify incantations required for AT&T 3B2's X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 1.90 04Mar93 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * handle -b (both .data and .rsrc at same time) option X * ( -> MacBinary suggested by bb@math.ufl.edu) X * remove anomalous file extension handling X * (suggested by bb@math.ufl.edu) X * regularize MAC_EDITOR (author) and MAC_FILETYPE (file type) handling X * detect and report important file format errors X * emit output file name too X * revise Usage line X * massively revise man page to reflect changes and generally overhaul X * ----- X * Internal X * ----- X * avoid overwriting internal storage (what a chore!) X * for example, mcvert -UI *.hqx used to abort with a segmentation violation X * symptom reported by franklin@eecs.ucdavis.edu Thu Sep 24 16:39:21 1992 X * check return values from all getc/putc operations X * find and fix ancient bug extracting resource fork from MacBinary format X * identify failing file in EOF error messages X * clarify and amend distribution and update restrictions X * expand disclaimer (patterned after INFO-MAC CD-ROM -- Thx, Cliff and Joe!) X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com} X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud X * Version 2.00 28Feb93 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * unixify all relevent output files X * (replace suspect characters with _) X * macify all relevent MacBinary files X * (replace suspect chars with -, take first 20 and last 11 if > 31 char) X * avoiding Mac file name > 31 chars (Rick Zaccone zaccone@bucknell.edu) X * always emit the Macintosh file name in the converting messages X * since the UNIX file names are now provided by default X * rework man page to bring it more up to date, added OTHER SOURCES section X * emit data and rsrc len when printing bin header X * report the input character, not the mapped character, if avail, X * else report mapped value as hex X * add -VV (Very Verbose) option X * ----- X * Internal X * ----- X * distribute mcvert.idraw, a postscript file X * describing mcvert options and transformations pictorially, X * contributed by Brian Bartholomew - bb@math.ufl.edu X * create and distribute README-conversion file X * update Makefile and README to make it more obvious how to build mcvert X * problem reported by David Micklethwaite <mickles@cherax.super.csiro.au> X * make s/S/v/V flag processing serially reusable X * avoid obsolete ftime on HP-UX, SunOS, DomainOS -- default is now -DTIMEVAL X * problem reported by smith@sfu.ca (Richard Smith) and X * Adam Harris (harris@cs.uchicago.edu) X * avoid SGI bug regarding unterminated character constant within #ifdef notdef X * problem reported by smith@sfu.ca (Richard Smith) X * clean up some FILE confusion X * make the man page work well across platforms X * re-lint on SunOS and HP-UX X * add various additional comments X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@wv.MentorG.com,Joseph_Skudlarek@MentorG.com} X * Version 2.09 30Jun93 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * ----- X * Internal X * ----- X * incorporate SCO UNIX requirements into the Makefile X * info from Fred Lenk, Camarillo, CA [fredgl@tecnet1.jcte.jcs.mil] X * backout intermediate XOBJ cleanup and continue to do what works for AT&T 3B2 X * belated & current thanks to Larry S. Staples [attjpn!lss@attibr.att.com] X * for providing and proofing the working recipe for AT&T 3B2 X * change OTHER SOURCES to OTHER PROGRAMS in man page, and mention programs X * which run on the Mac, including CompactPro, StuffIt, and BinHex 4.0 X * ship the formatted ASCII version of the man page for those without nroff X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@wv.MentorG.com,Joseph_Skudlarek@MentorG.com} X * Version 2.12 19Jul93 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * ----- X * Internal X * ----- X * add StuffIt Expander mention to man page X * suggest using text (-t|-u) if data is text in the data (-d) description X * incorporate AIX Makefile improvement provided by X * DaviD W. Sanderson (dws@ssec.wisc.edu) X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@wv.MentorG.com,Joseph_Skudlarek@MentorG.com} X * Version 2.13 13Sep93 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * add -P (pipe to stdout) option X * capability requested by lentz@rossi.astro.nwu.edu (Robert Lentz) X * have all info messages go to stderr, not stdout, to faciliate -P X * (undo converting msg to stdout from version 1.6.5, dated Oct 1991) X * update man page to indicate changes X * ----- X * Internal X * ----- X * fiddle with info message to make it a bit clearer X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@wv.MentorG.com,Joseph_Skudlarek@MentorG.com} X * Version 2.14 10Nov93 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * ----- X * Internal X * ----- X * ensure all source line lengths are less than 80 X * after someone or something wrapped the 2.14 archive, and it X * would not compile (split a character string literal). X * Thanks to Robert Hagopian (rhagopia@terminator.rs.itd.umich.edu) X * and to L L Campbell (campbell@brahms.udel.edu) for bringing this X * problem to my attention. X * [recall that shar usually prepends X, which bumps the line length by 1] X * [also, < 80 makes editing with emacs at 80 columns a bit better] X * add check_linelen to Makefile to help ensure compliance X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@wv.MentorG.com,Joseph_Skudlarek@MentorG.com} X * Version 2.15 15Nov93 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * External X * ----- X * ----- X * Internal X * ----- X * fix original bug of failing to convert lengths when extracting data X * and resource forks from MacBinary files -- thanks to Thomas Lange X * <tlange@namu01.gwdg.de> for finding and supplying the fix for this bug X * tidy up for Alpha OSF1 -- thanks to Holger Debelts X * <Debelts@rrz.Uni-Koeln.DE> for providing a fix for time()'s redeclaration X * check <= 80 on *archive*, and avoid always rebuilding shar X * due to unfulfilled check_linelen dependency X * improve 2.15 comments X * toss uninteresting lint messages X * ----- X * Joseph Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 X * (503) 685-1576 (work) X * {Jskud@wv.MentorG.com,Joseph_Skudlarek@MentorG.com} X * Version 2.16 14Oct94 X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * This program may be freely distributed for non-profit purposes. It X * may not be sold, by itself or as part of a collection of software. X * However, it may be distributed in source form with large X * collections of freeware and shareware, such as the INFO-MAC CD-ROM, X * which charge only a modest fee for publishing, but not selling, the X * software. It may be freely modified as long as no modified version X * is independently distributed. Modifications of interest to all can X * be incorporated into the program by sending them to me for X * inclusion and redistribution, or by releasing an updated mcvert to X * the info-mac archives. Parts of the code can be used in other X * programs. We hope you find mcvert useful, and enjoy using it. X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * DISCLAIMER -- USE mcvert software AT YOUR OWN RISK X * This mcvert software is provided "as is" without warrantee of any X * kind. The entire risk as to the results and performance of the X * software is assumed by you, and in no event will we be liable for X * any consequential, incidental, or indirect damages suffered in the X * course of using this software. X * ---------------------------------------------------------------------------- X X * ---------------------------------------------------------------------------- X * Things that yet could be done: X * --- X * handle incoming BinHex4.0 files with ^M instead of ^J X * (requested by jonathan brecher brecher@husc.harvard.edu 29Mar93) X * eg, right now we toss the entire line if it doesn't start with a colon X * but the start of the line could be later on, following a ^M X * check for more file format errors, eg, MacBinary must be multiple of 128 X * option to avoid .text extension on write (Rick Zaccone zaccone@bucknell.edu) X * check return values from fputs/fprintf X * provide header heuristic tuning option: set length and/or same sensitivity X * ---------------------------------------------------------------------------- X */ X /* X * Naming X * DOWNLOAD X * => converting TO MacBinary X * => direction == FORWARDS X * => use un_* routines (un => UNdo encoding?) X * UPLOAD X * => converting FROM MacBinary X * => direction == BACKWARDS X * => use re_* routines (re => Really Encode?) X */ X #include "mactypes.h" X /* it would be natural to use an enum here, but avoid "fancy" features */ #define HQX 0 #define TEXT 1 #define DATA 2 #define RSRC 3 #define BOTH 5 X #define FORWARDS 0 #define BACKWARDS 1 X FILE *devnull; FILE *convert; FILE *verbose; FILE *debug; int Debug; X char **hqxnames, **hqxnames_left; char *dir, *ext, *mac_auth, *mac_type; int translate_eol; char *maxlines_str; int maxlines; X /* used to skip suspect mail header lines */ int suspect_shorter = 12; int suspect_same = 1; X /* used to avoid writing output files */ int info_only; X /* pipe appropriate output -- write to stdout */ int pipe_out; X char Usage[] = "\ Usage: %s { [option] ... name ...} ...\n\ X version:\t%4.2f\n\ X default:\t-xDqv\n\ \n\ X option:\n\ \t-x\tBinHex .hqx <-> MacBinary\n\ \t-u\tText(trans) .text <-> MacBinary\n\ \t-h\tHost(as is) .text <-> MacBinary\n\ \t-d\tData .data <-> MacBinary\n\ \t-r\tResource .rsrc <-> MacBinary\n\ \t-b\tBoth .data .rsrc <-> MacBinary\n\ \n\ \t-D\tDownload Other -> MacBinary\n\ \t-U\tUpload MacBinary -> Other\n\ \n\ \t-p\tBinHex -> MacBinary => unpack PIT\n\ \t-q\tdisable unpack PIT\n\ \t-t\ttranslate end-of-line chars (useful with -b)\n\ \n\ \t-I\tInformation only (does not write output files)\n\ \t-P\tPipe output to stdout\n\ \t-s\tsilent\n\ \t-S\tSilent about ``Converting ... '' lines too\n\ \t-v\tverbose\n\ \t-V\tVerbose, includes debugging information\n\ \t-VV\tVery Verbose, includes extra debugging information\n\ \t-H\tdisable skip-legal-but-suspect-lines Heuristic\n\ \n\ Environment:\n\ \tMAC_FILETYPE \tTEXT|????\tMac file type for Text|other\n\ \tMAC_EDITOR \tMACA|????\tMac creator (author) for Text|other\n\ \tMAC_EXT \t.bin \textension for -D\n\ \tMAC_DLOAD_DIR \t. \tdirectory for -D\n\ \tMAC_LINE_LIMIT\tnone \tmaximum line length for -Ux\n\ "; X char *cmdname; X main(argc, argv) X int argc; X char **argv; { X char *flags, *getenv(); X int direction, mode, unpit_flag; X X cmdname = argv[0]; X X /* Early error and clean exit if missing arguments */ X if (argc < 2) { X usage(); X /*NOTREACHED*/ X } X X devnull = fopen("/dev/null", "w+"); X X argv++; X argc--; X X convert = stderr; X verbose = stderr; X debug = devnull; X Debug = 0; X X direction = FORWARDS; X mode = HQX; X unpit_flag = 0; X X mac_type = getenv("MAC_FILETYPE"); X mac_auth = getenv("MAC_EDITOR"); X X if ((ext = getenv("MAC_EXT")) == NULL) X ext = ".bin"; X if ((dir = getenv("MAC_DLOAD_DIR")) == NULL) X dir = "."; X if ((maxlines_str = getenv("MAC_LINE_LIMIT")) == NULL) X maxlines = 0; X else { X maxlines = atoi(maxlines_str); X if (maxlines < MIN_HQX_LINES) { X fprintf(stderr, "%s: %s; was %d; reset to %d\n", X cmdname, X "warning: MAC_LINE_LIMIT too small", X maxlines, MIN_HQX_LINES); X fflush(stderr); X maxlines = MIN_HQX_LINES; X } X } X X /* Make command line arguments globally accessible */ X hqxnames = (char **) calloc((unsigned)argc + 1, sizeof(char *)); X hqxnames_left = hqxnames; X while (argc--) X *hqxnames_left++ = *argv++; X X /* Flag the end of the list */ X *hqxnames_left = "-"; X hqxnames_left = hqxnames; X X /* While not at the end of the list */ X while (strcmp(*hqxnames_left, "-")) { X translate_eol = 0; X if (hqxnames_left[0][0] == '-') { X flags = *hqxnames_left++; X while (*++flags) X switch (*flags) { X case 'x': X mode = HQX; X break; X case 'u': X translate_eol = 1; X mode = TEXT; X break; X case 'd': X mode = DATA; X break; X case 'r': X mode = RSRC; X break; X case 'h': X translate_eol = 0; X mode = TEXT; X break; X case 'b': X mode = BOTH; X break; X case 't': X translate_eol = 1; X break; X case 'D': X direction = FORWARDS; X break; X case 'U': X direction = BACKWARDS; X break; X case 'q': X unpit_flag = 0; X break; X case 'p': X unpit_flag = 1; X break; X case 'S': X convert = devnull; X verbose = devnull; X debug = devnull; X Debug = 0; X break; X case 's': X convert = stderr; X verbose = devnull; X debug = devnull; X Debug = 0; X break; X case 'v': X convert = stderr; X verbose = stderr; X debug = devnull; X Debug = 0; X break; X case 'V': X convert = stderr; X verbose = stderr; X debug = stderr; X Debug++; X break; X case'H': X suspect_shorter = suspect_same = 0; X break; X case 'I': X info_only = 1; X break; X case 'P': X pipe_out = 1; X break; X default: X usage(); X /*NOTREACHED*/ X } X } X X if (direction == BACKWARDS) X if (mode == HQX && unpit_flag) X re_hqx(); /* no re_pit() yet */ X else if (mode == HQX) X re_hqx(); X else X re_other(mode); X else if (mode == HQX) X un_hqx(unpit_flag); X else X un_other(mode); X } X X exit(0); X /*NOTREACHED*/ } X /* An array useful for CRC calculations that use 0x1021 as the "seed" */ word magic[] = { X 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, X 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, X 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, X 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, X 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, X 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, X 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, X 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, X 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, X 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, X 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, X 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, X 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, X 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, X 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, X 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, X 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, X 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, X 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, X 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, X 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, X 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, X 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, X 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, X 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, X 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, X 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, X 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, X 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, X 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, X 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, X 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; X X /* X * calc_crc() -- X * Compute the MacBinary II-style CRC for the data pointed to by p, with the X * crc seeded to seed. X * X * Modified by Jim Van Verth to use the magic array for efficiency. X */ short calc_mb_crc(p, len, seed) X unsigned char *p; X long len; X short seed; { X short hold; /* crc computed so far */ X long i; /* index into data */ X X extern unsigned short magic[]; /* the magic array */ X X hold = seed; /* start with seed */ X for (i = 0; i < len; i++, p++) { X hold ^= (*p << 8); X hold = (hold << 8) ^ magic[(unsigned char) (hold >> 8)]; X } X X return (hold); } /* calc_crc() */ X X /* Report a fatal error, and exit, never return */ error(msg, name) X char msg[], name[]; X { X fprintf(stderr, msg, name); X (void)putc('\n', stderr); X perror("\nlast perror (may not be relevant)"); X fprintf(stderr, "%s: exiting\n", cmdname); X if (debug == stderr) X abort(); X exit(2); X /*NOTREACHED*/ } X /* replace illegal Unix characters in file name */ /* make sure host file name doesn't get truncated beyond recognition */ unixify(np) X register char *np; { X register ulong c; X X c = strlen(np); X if (c > SYSNAMELEN - MAXEXTENSION) X c = SYSNAMELEN - MAXEXTENSION; X np[c] = '\0'; X X /* pre-decrement to match pre-increment within loop */ X np--; X while (c = *++np) X /* X * that is, ``if control or blank, or slash, or delete or 8bit'' X * which is the same as ``if blank, slash, or non graphic'' X */ X if (c <= ' ' || c == '/' || c > '~') X *np = '_'; } X /* X * replace illegal Macintosh characters in file name X * return resulting length X * X * According to Inside Macintosh, IV-90, valid file names X * must be [1..31] characters long X * must not contain a colon X * must contain only printing characters X */ macify(name, len, translate) X char *name; X int len; X int translate; { X register char *np; X register ulong c; X char *s, *t; X char buffer[SYSNAMELEN]; X X /* make a copy to ensure null terminated */ X strncpy(buffer, name, len); X buffer[len] = 0; X np = buffer; X X if (len < 1) X error("incoming file name is null", ""); X if (len > 31) { X /* too long, so just take first 20 and last 11 */ X s = np + 20; X t = np + len - 11; X while (*s++ = *t++) X ; X len = 31; X } X X if (translate) { X /* pre-decrement to match pre-increment within loop */ X np--; X while (c = *++np) X X /* X X * Inside Macintosh, I-246, defines the printable characters X * for the Macintosh as 0x20 thru 0xD8 less 0x7F. Yet, the X * apple character is above this range, at 0xF0, and the diamond X * character is below this range, at 0x13. And Adobe Garamond X * has lots of characgters above 0xD8. X * X * On the other hand, we only translate when processing UNIX X * file names which are usually ASCII, and ASCII printables are X * ' ' <= valid <= '~'. X * X * But we want to avoid zapping any characters with the high X * order bit set, so 8 bit character users are not zinged. I've X * never used a SONY-NeWS box, but this one's for you. But how X * do we know if/that the UNIX and Macintosh extended characters X * are the same? X * X * So what to do, what to do? X * X * Let's look at it this way: if the UNIX file name has extended X * characters in it, they got there for a reason, hopefully on X * purpose, and we'll not gratuitously modify them. X * X * And it looks like the 6.1.5 Finder running with the 6.0.5 X * System will translate both control characters and colon into X * a dash, but leave the others alone, so so will we. X * X * I don't know if MacOS, as opposed to the Finder, behaves X * differently, and it's too late tonight to find out. Maybe X * some other time. X X */ X X if (c < ' ' || c == ':' || c == '\177') X *np = '-'; X } X X /* copy the resulting string back in place */ X strncpy(name, buffer, len); X X return len; } X /* X * Unix time (GMT since 1-1-1970) X * Mac time (local since 1-1-1904) X */ #define MACTIMEDIFF 0x7c25b080 /* Mac time of 00:00:00 GMT, Jan 1, 1970 */ X /* Convert Unix time to Mac time */ ulong unix2mac(xtime) X ulong xtime; { #ifdef TIMEVAL X struct timeval t; X struct timezone tz; X X gettimeofday(&t, &tz); X return long2mac(xtime + MACTIMEDIFF X - 60 * (tz.tz_minuteswest - 60 * tz.tz_dsttime)); #else X struct timeb tp; X X ftime(&tp); X return long2mac(xtime + MACTIMEDIFF X - 60 * (tp.timezone - 60 * tp.dstflag)); #endif } X /* Convert Mac time to Unix time */ ulong mac2unix(xtime) X ulong xtime; { #ifdef TIMEVAL X struct timeval t; X struct timezone tz; X X gettimeofday(&t, &tz); X return (mac2long(xtime) - MACTIMEDIFF X + 60 * (tz.tz_minuteswest - 60 * tz.tz_dsttime)); #else X struct timeb tp; X X ftime(&tp); X return (mac2long(xtime) - MACTIMEDIFF X + 60 * (tp.timezone - 60 * tp.dstflag)); #endif } X /* X * computes the appropriate output files X * and the appropriate optional suffixes, X * all depending on the processing "mode" X */ X mode_to_fname_suffix( X mode, base_fname, data_fname, data_suffix, rsrc_fname, rsrc_suffix ) X int mode; X char *base_fname, *data_fname, **data_suffix, *rsrc_fname, **rsrc_suffix; { X X /* clear names to indicate nothing selected yet */ X *data_fname = *rsrc_fname = 0; X X switch (mode) { X case TEXT: X strcpy(data_fname, base_fname); X *data_suffix = ".text"; X break; X case DATA: X strcpy(data_fname, base_fname); X *data_suffix = ".data"; X break; X case RSRC: X strcpy(rsrc_fname, base_fname); X *rsrc_suffix = ".rsrc"; X break; X case BOTH: X strcpy(data_fname, base_fname); X strcat(data_fname, ".data"); X *data_suffix = ""; X strcpy(rsrc_fname, base_fname); X strcat(rsrc_fname, ".rsrc"); X *rsrc_suffix = ""; X break; X default: X error("Internal error: unexpected mode", ""); X break; X } } X /* X This procedure basically copies the input file(s) to the output X MacBinary file; in TEXT (translate_eol) mode it changes LF's to X CR's, and in any mode it forges a Mac info header. Author type X comes from the MAC_EDITOR environment variable if it is defined. X */ X un_other(mode) X int mode; { X char data_fname[SYSNAMELEN], rsrc_fname[SYSNAMELEN], binfname[SYSNAMELEN]; X FILE *data_file, *rsrc_file, *binfile; X char *base_fname, *data_suffix, *rsrc_suffix; X struct stat data_stbuf, rsrc_stbuf; X ulong dlen, rlen, mtim, ctim; X X info_header info; X register ulong b; /* not character, must hold EOF diagnostic */ X register ulong nchars; X int extra_chars; X short crc; X long len; X X while (hqxnames_left[0][0] != '-') { X X if (strlen(*hqxnames_left) >= SYSNAMELEN) X error("Error: specified base file name is too long", ""); X base_fname = *hqxnames_left++; X X /* set up file names */ X mode_to_fname_suffix(mode, base_fname, X data_fname, &data_suffix, rsrc_fname, &rsrc_suffix); X X /* process the data file, if requested */ X dlen = 0; X if (*data_fname) { X data_file = mopen(data_fname, data_suffix, "r"); X if (fstat(fileno(data_file), &data_stbuf)) X error("Cannot stat %s", data_fname); X mtim = unix2mac((ulong)data_stbuf.st_mtime); X ctim = unix2mac((ulong)data_stbuf.st_ctime); X dlen = long2mac(data_stbuf.st_size); X } X X /* process the rsrc file, if requested */ X rlen = 0; X if (*rsrc_fname) { X rsrc_file = mopen(rsrc_fname, rsrc_suffix, "r"); X if (fstat(fileno(rsrc_file), &rsrc_stbuf)) X error("Cannot stat %s", rsrc_fname); X mtim = unix2mac((ulong)rsrc_stbuf.st_mtime); X ctim = unix2mac((ulong)rsrc_stbuf.st_ctime); X rlen = long2mac(rsrc_stbuf.st_size); X } X X /* stuff header data into the info header */ X X bzero((char*)&info, sizeof(info_header)); X X info.nlen = strlen(base_fname); X info.nlen = (info.nlen > NAMELEN) ? NAMELEN : info.nlen; X strncpy((char*)info.name, base_fname, (int)info.nlen); X X /* now make sure the resulting name is valid */ X info.nlen = macify((char*)info.name, (int)info.nlen, 1); X X info.uploadvers = '\201'; X info.readvers = '\201'; X X bcopy((char*)&mtim, (char*)info.mtim, 4); X bcopy((char*)&ctim, (char*)info.ctim, 4); X X bcopy((char*)&dlen, (char*)info.dlen, 4); X bcopy((char*)&rlen, (char*)info.rlen, 4); X X switch (mode) { X case TEXT: X bcopy(mac_type ? mac_type : "TEXT", (char*)info.type, 4); X bcopy(mac_auth ? mac_auth : "MACA", (char*)info.auth, 4); X break; X case DATA: X case RSRC: X case BOTH: X bcopy(mac_type ? mac_type : "????", (char*)info.type, 4); X bcopy(mac_auth ? mac_auth : "????", (char*)info.auth, 4); X break; X default: X error("Internal error: unexpected mode", ""); X break; X } X X /* calculate CRC */ X crc = calc_mb_crc((unsigned char*)&info, 124L, 0); X info.crc[0] = (char) (crc >> 8); X info.crc[1] = (char) crc; X X /* Create the .bin file and write the info to it */ X X len = strlen(dir) + strlen(base_fname) + strlen(ext) + 1; X if (len >= sizeof(binfname)) X error("Error: generated binfname would be too long", ""); X /* X * base_fname does not need to be unixified -- X * was valid coming in X */ X sprintf(binfname, "%s/%s%s", dir, base_fname, ext); X binfile = mopen(binfname, "", "w"); X X converting(info.name, (int)info.nlen, info.type, info.auth); X print_bin_hdr("Creating", &info); X if (1 != fwrite((char*)&info, sizeof(info), 1, binfile)) X error("fwrite failed on binfile", ""); X X /* pump out the data portion */ X if (*data_fname) { X nchars = data_stbuf.st_size; X extra_chars = 127 - (nchars + 127) % 128; X X if (translate_eol) X while (nchars--) { X (b = getc(data_file)) == EOF && X error("Error: getc failed on data_file", ""); X if (b == LF) X b = CR; X putc((char)b, binfile) == EOF && X error("Error: putc failed on binfile", ""); X } X X else X while (nchars--) { X (b = getc(data_file)) == EOF && X error("Error: getc failed on data_file", ""); X putc((char)b, binfile) == EOF && X error("Error: putc failed on binfile", ""); X } X X while (extra_chars--) { X putc(0, binfile) == EOF && X error("Error: putc failed on binfile", ""); X } X X mclose(&data_file, "txtfile"); X } X X /* pump out the rsrc portion */ X if (*rsrc_fname) { X nchars = rsrc_stbuf.st_size; X extra_chars = 127 - (nchars + 127) % 128; X X while (nchars--) { X (b = getc(rsrc_file)) == EOF && X error("Error: getc failed on rsrc_file", ""); X putc((char)b, binfile) == EOF && X error("Error: putc failed on binfile", ""); X } X X while (extra_chars--) { X putc(0, binfile) == EOF && X error("Error: putc failed on binfile", ""); X } X X mclose(&rsrc_file, "txtfile"); X } X X mclose(&binfile, "binfile"); X } } X /* X This procedure basically copies the MacBinary input file to the X output file(s); in TEXT (translate_eol) mode it changes CR's to X LF's, and in any mode it skikps over the Mac info header. X */ X re_other(mode) X int mode; { X char base_fname[SYSNAMELEN]; X char data_fname[SYSNAMELEN], rsrc_fname[SYSNAMELEN], binfname[SYSNAMELEN]; X FILE *data_file, *rsrc_file, *binfile; X char *data_suffix, *rsrc_suffix; X X info_header info; X register ulong b; X register ulong nchars; X ulong temp; X int extra_chars; X long len; X X while (hqxnames_left[0][0] != '-') { X X /* suck in the MacBinary header */ X if (strlen(*hqxnames_left) >= sizeof(binfname)) X error("Error: specified binfname is too long", ""); X strcpy(binfname, *hqxnames_left++); X binfile = mopen(binfname, ext, "r"); X if (1 != fread((char*)&info, sizeof(info), 1, binfile)) X error("fread failed on binfile", ""); X X /* figure out the target base file name */ X if (info.nlen >= NAMELEN) X error("Error: corrupt BinHex data format", ""); X strncpy(base_fname, (char*)info.name, (int)info.nlen); X base_fname[info.nlen] = '\0'; X converting(info.name, (int)info.nlen, info.type, info.auth); X print_bin_hdr("Reading", &info); X X /* ensure the output files have no bogus UNIX characters */ X unixify(base_fname); X mode_to_fname_suffix(mode, base_fname, X data_fname, &data_suffix, rsrc_fname, &rsrc_suffix); X X /* always use suffix on write */ X X if (*data_fname) { X len = strlen(data_fname) + strlen(data_suffix); X if (len >= sizeof(data_fname)) X error("Error: generated data_fname would be too long", ""); X strcat(data_fname, data_suffix); X data_file = mopen(data_fname, "", "w"); X } X X if (*rsrc_fname) { X len = strlen(rsrc_fname) + strlen(rsrc_suffix); X if (len >= sizeof(rsrc_fname)) X error("Error: generated rsrc_fname would be too long", ""); X strcat(rsrc_fname, rsrc_suffix); X rsrc_file = mopen(rsrc_fname, "", "w"); X } X X /* process the data fork */ X bcopy((char*)info.dlen, (char *) &temp, 4); X nchars = mac2long(temp); X extra_chars = 127 - (nchars + 127) % 128; X X if (*data_fname) { X X if (translate_eol) X while (nchars--) { X (b = getc(binfile)) == EOF && X error("Error: getc failed on binfile", ""); X if (b == CR) X b = LF; X putc((char)b, data_file) == EOF && X error("Error: putc failed on data_file", ""); X } X X else X while (nchars--) { X (b = getc(binfile)) == EOF && X error("Error: getc failed on binfile", ""); X putc((char)b, data_file) == EOF && X error("Error: putc failed on data_file", ""); X } X X mclose(&data_file, data_fname); X X } else { X X /* skip the actual data */ X while (nchars--) { X getc(binfile) == EOF && X error("Error: getc failed on binfile", ""); X } X } X X /* eat the padding to 128 byte boundary */ X while (extra_chars--) { X getc(binfile) == EOF && X error("Error: getc failed on binfile", ""); X } X X /* process the rsrc fork */ X X bcopy((char*)info.rlen, (char *) &temp, 4); X nchars = mac2long(temp); X X if (*rsrc_fname) { X while (nchars--) { X (b = getc(binfile)) == EOF && X error("Error: getc failed on binfile", ""); X putc((char)b, rsrc_file) == EOF && X error("Error: putc failed on rsrc_file", ""); X } X mclose(&rsrc_file, rsrc_fname); X } X X mclose(&binfile, "binfile"); X } } X usage() { X fprintf(stderr, Usage, cmdname, VERSION/100.); X exit(1); X /*NOTREACHED*/ } X X /* My FileIO routines, to enable clean implementation of info_only */ /* If info_only and open for write, inform user and use devnull instead */ /* If pipe_out and open for write, inform user and use stdout instead */ /* If trying to close devnull or stdout, don't */ X FILE * mopen(name, exten, type) X char *name; X char *exten; X char *type; { X FILE *result; X X switch (*type) { X case 'r': X result = fopen(name, type); X if (result == NULL && *exten) { X /* see if adding the extension would help */ X int len_root = strlen(name); X int len_ext = strlen(exten); X char *dotspot = name + len_root - len_ext; X if (strcmp(exten, dotspot)) { X if (len_root + len_ext >= SYSNAMELEN) X error("Error: generated file name would be too long", ""); X strcat(name, exten); X result = fopen(name, type); X } X } X if (result == NULL) X error("Cannot open %s for read", name); X else { X fprintf(verbose, "\n%-15s%-27s\n", X "Input file", name); X fflush(verbose); X } X break; X X case 'w': X if (info_only) { X fprintf(verbose, " %-14s%-27s -I (info only) specified\n", X " No output to", name); X fflush(verbose); X result = devnull; X } else if (pipe_out) { X fprintf(verbose, " %-14s%-27s -P (pipe to stdout) specified\n", X " stdout, vice", name); X fflush(verbose); X result = stdout; X } else { X result = fopen(name, type); X if (result == NULL) X error("Cannot open %s for write", name); X else { X fprintf(verbose, "%-15s%-27s\n", X "Output file", name); X fflush(verbose); X } X } X break; X X default: X fprintf(stderr, "%s: internal error in mopen -- exiting\n", cmdname); X exit(2); X X } X X return result; } X mclose(stream_p, name) X FILE **stream_p; X char *name; { X if (*stream_p && *stream_p != devnull && *stream_p != stdout) { X if (fclose(*stream_p) == EOF) X error("Error closing %s", name); X } X X *stream_p = (FILE *)0; } X converting(name, len, type, auth) X byte *name; X int len; X byte *type; X byte *auth; { X char buffer[SYSNAMELEN]; X X /* make a copy to ensure null terminated */ X strncpy(buffer, (char*)name, len); X buffer[len] = 0; X X fprintf(convert, X "%-15s%-30s type = \"%4.4s\", author = \"%4.4s\"\n", X info_only ? "Inspecting" : "Converting", X buffer, type, auth); X fflush(convert); } X print_bin_hdr(msg, hdr) X char *msg; X info_header *hdr; { X ulong otime, xtime; X long dlen, rlen; X bcopy((char*)hdr->ctim, (char*)&otime, 4); X DEBUG && fprintf(debug, X "DEBUG: verifying mac2unix/unix2mac: 0x%8lx, 0x%8lx\n", X otime, unix2mac(mac2unix(otime))); X X bcopy((char*)hdr->dlen, (char*)&dlen, 4); X bcopy((char*)hdr->rlen, (char*)&rlen, 4); X X DEBUG && fprintf(debug, "\ %s\n\ \tName %.*s\n\ \tType %.4s\n\ \tCreator %.4s\n\ \tDataLen %ld\n\ \tRsrcLen %ld\n\ ", X msg, X hdr->nlen, hdr->name, X hdr->type, X hdr->auth, X mac2long(dlen), X mac2long(rlen), X 0); X X bcopy((char*)hdr->ctim, (char*)&otime, 4); X xtime = mac2unix(otime); X DEBUG && fprintf(debug, "raw ctim: 0x%8lx, mac2unix: 0x%8lx\n", X otime, xtime); X DEBUG && fflush(debug); X X fprintf(verbose, "\tCreated %s", ctime((time_t *)&xtime)); X fflush(verbose); X X bcopy((char*)hdr->mtim, (char*)&otime, 4); X xtime = mac2unix(otime); X DEBUG && fprintf(debug, "raw mtim: 0x%8lx, mac2unix: 0x%8lx\n", X otime, xtime); X DEBUG && fflush(debug); X fprintf(verbose, "\tModified %s", ctime((time_t *)&xtime)); X fflush(verbose); X } SHAR_EOF chmod 0444 mcvert.c || echo 'restore of mcvert.c failed' Wc_c="`wc -c < 'mcvert.c'`" test 45667 -eq "$Wc_c" || echo 'mcvert.c: original size 45667, current size' "$Wc_c" fi # ============= hqxify.c ============== if test -f 'hqxify.c' -a X"$1" != X"-c"; then echo 'x - skipping hqxify.c (File already exists)' else echo 'x - extracting hqxify.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'hqxify.c' && #include "mactypes.h" X /* HQXBUFLEN must be large enough to hold a complete hqx header */ #define HQXBUFLEN 512 byte hqxbuf[HQXBUFLEN + 1], *buf_ptr, *buf_end, *buf_start = hqxbuf + 1; X /* Note: line[0] stores the run length character, X * so line is one greater than MAXLINE */ #define MAXLINE 2048 byte line[MAXLINE + 1], *line_ptr, *line_end, *line_start = line + 1; X /* keep the compiler happy */ #define LINE_START ((char*)(line_start)) X extern char *cmdname; X int line_count, file_count; int save_state, total_bytes, save_run_length; word save_accum; char binfname[SYSNAMELEN], hqxfname[SYSNAMELEN]; FILE *hqxfile, *binfile; X /* X * hqxsuspect caches whether or not we have gotten past all suspect data X * at the head of a file, for example, a mail header. hqxsuspect is set X * on every new hqx file read and on detecting bogus lines, X * and reset only in non_suspect(). X */ int hqxsuspect; extern suspect_shorter; extern suspect_same; X extern int info_only; X /* This routine reads the header of a hqxed file and appropriately twiddles it, X determines if it has CRC problems, creates the .bin file, and puts the info X into the .bin file. X Output is hqx_datalen, hqx_rsrclen, type, binfname, binfile. X Returns 0 iff failed to read header. X */ X X int hqx_to_bin_hdr(type, hqx_datalen, hqx_rsrclen, same_file_only) X char *type; X ulong *hqx_datalen, *hqx_rsrclen; X int same_file_only; { X register byte *hqx_ptr, *hqx_end; X register ulong calc_crc; X hqx_buf *hqx_block; X hqx_header *hqx; X info_header info; X ulong mtim; X short crc; X long len; X X extern word magic[]; X extern char *dir, *ext; X extern short calc_mb_crc(); X X /* read the hqx header, X * assuming that I won't exhaust hqxbuf in so doing -- X * that is, that hqxbuf is always large enough (it is) X */ X (void)fill_hqxbuf(same_file_only); X /* X * If we are reading multiple files, then we could have the last X * unread line of the "previous" file be just a colon (since we are X * length driven, and stopped when we processed the expected X * lengths), and the prior fill_hqxbuf() call would find it and X * return 0, leaving the buffer unfilled. So, if we have zero X * bytes so far, just fill it again. X */ X if (total_bytes == 0) { X DEBUG && fprintf(debug, X "%s: Note: had to call fill_hqxbuf again in hqx_to_bin_hdr\n", X cmdname); X DEBUG && fflush(debug); X (void)fill_hqxbuf(same_file_only); X } X if (same_file_only == 1 && total_bytes == 0) X return 0; X if (total_bytes < MIN_HQX_HDR) { X fprintf(verbose, "%s: %s (%d < %d): bad file format? -- exiting\n", X cmdname, "error: hqx_header too short", total_bytes, MIN_HQX_HDR); X fflush(verbose); X exit(2); X } X X hqx_block = (hqx_buf *) buf_ptr; X hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen); X hqx_ptr = buf_ptr; X hqx_end = (byte *) hqx + sizeof(hqx_header) - 1; X calc_crc = 0; X while (hqx_ptr < hqx_end) X calc_crc = (((calc_crc & 0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8]; X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8]; X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8]; X buf_ptr = hqx_ptr; X X /* stuff the hqx header data into the info header */ X bzero((char*)&info, sizeof(info_header)); X info.nlen = hqx_block->nlen; X if (info.nlen > sizeof(info.name)) X error("Error: corrupt BinHex data format", ""); X strncpy((char*)info.name, (char*)hqx_block->name, (int)info.nlen);/* name */ X X /* now make sure the resulting name is valid for length only */ X info.nlen = macify((char*)info.name, (int)info.nlen, 0); X X bcopy((char*)hqx->type, (char*)info.type, 9); /* type, author, flag */ X info.flags &= 0x7e; /* reset lock bit, init bit */ X if (hqx->protect & 0x40) X info.protect = 1; /* copy protect bit */ X bcopy((char*)hqx->dlen, (char*)info.dlen, 8); /* dlen, rlen */ X mtim = unix2mac((ulong)time((long*)0)); X bcopy((char*)&mtim, (char*)info.mtim, 4); X bcopy((char*)&mtim, (char*)info.ctim, 4); X info.uploadvers = '\201'; X info.readvers = '\201'; X X /* calculate MacBinary CRC */ X crc = calc_mb_crc((unsigned char*)&info, 124L, 0); X info.crc[0] = (char) (crc >> 8); X info.crc[1] = (char) crc; X X /* Create the .bin file and write the info to it */ X X unixify((char*)hqx_block->name); X converting(info.name, (int)info.nlen, info.type, info.auth); X print_bin_hdr("Creating", &info); X X len = strlen(dir) + strlen((char*)hqx_block->name) + strlen(ext) + 1; X if (len >= sizeof(binfname)) X error("Error: generated binfname would be too long", ""); X sprintf(binfname, "%s/%s%s", dir, hqx_block->name, ext); X binfile = mopen(binfname, "", "w"); X X check_hqx_crc((word)calc_crc, "File header CRC mismatch in %s", binfname); X if (1 != fwrite((char*)&info, sizeof(info), 1, binfile)) X error("fwrite failed on binfile", ""); X X /* Get a couple of items we'll need later */ X bcopy((char*)info.dlen, (char*)hqx_datalen, 4); X *hqx_datalen = mac2long(*hqx_datalen); X bcopy((char*)info.rlen, (char*)hqx_rsrclen, 4); X *hqx_rsrclen = mac2long(*hqx_rsrclen); X bcopy((char*)info.type, (char*)type, 4); X X /* emit useful debugging info */ X DEBUG && fprintf(debug, "\tdata_len=%10ld\t\trsrc_len=%10ld\n", X *hqx_datalen, *hqx_rsrclen); X DEBUG && fflush(debug); X X return 1; } X /* This routine reads the header of a bin file and appropriately twiddles it, X creates the .hqx file, and puts the info into the .hqx file. X Output is hqx_datalen, hqx_rsrclen, type, hqxfname, hqxfile */ X bin_to_hqx_hdr(hqx_datalen, hqx_rsrclen) X ulong *hqx_datalen, *hqx_rsrclen; { X register byte *hqx_ptr, *hqx_end; X register ulong calc_crc; X hqx_buf *hqx_block; X hqx_header *hqx; X info_header info; X extern word magic[]; X extern char **hqxnames_left; X extern char *ext; X long len; X X len = strlen(*hqxnames_left); X if (len >= sizeof(binfname)) X error("Error: specified binfname is too long", ""); X strcpy(binfname, *hqxnames_left++); X binfile = mopen(binfname, ext, "r"); X X if (!fread((char*)&info, sizeof(info), 1, binfile)) X error("Unexpected EOF in MacBinary header of %s", binfname); X X /* stuff the info header into the hqx header */ X hqx_block = (hqx_buf *) buf_ptr; X hqx_block->nlen = info.nlen; X if (info.nlen > sizeof(hqx_block->name)) X error("Error: corrupt MacBinary data format", ""); X strncpy((char*)hqx_block->name, (char*)info.name, (int)info.nlen); X /* X * We expect a valid Macintosh file name since it came from a MacBinary file X * so we don't potentially corrupt a valid copied name via macify translate. X * File name length should not be a problem, so we do nothing. X */ X hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen); X hqx->version = 0; X bcopy((char*)info.type, (char*)hqx->type, 9); /* type, author, flags */ X hqx->flags &= 0x7e; /* reset lock bit, init bit */ X if (info.protect == 1) X hqx->protect = 0; /* protect bit: 0x40 */ X else X hqx->protect = 0; X bcopy((char*)info.dlen, (char*)hqx->dlen, 8); /* dlen, rlen */ X X /* Create the .hqx file and write the info to it */ X #ifdef notdef X This is the right thing to check but the Sun optimizing X compiler gives a (valid) warning that info.nlen (one char, X 255 max) is always less than sizeofhqxfname) which is X hardwired to 1024 since version 1.99. Since we have already X checked info.nlen above, we skip the test and avoid the warning. X X if (info.nlen >= sizeof(hqxfname)) X error("Error: generated hqxfname would be too long", ""); #endif X X strncpy(hqxfname, (char*)info.name, (int)info.nlen); X hqxfname[info.nlen] = '\0'; X unixify(hqxfname); X converting(info.name, (int)info.nlen, info.type, info.auth); X print_bin_hdr("Reading", &info); X X calc_crc = 0; X hqx_ptr = (byte *) hqx_block; X hqx_end = hqx_ptr + hqx_block->nlen + sizeof(hqx_header); X while (hqx_ptr < hqx_end) X calc_crc = (((calc_crc & 0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8]; X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8]; X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8]; X buf_ptr = hqx_end; X write_hqx_crc((word)calc_crc); X X /* Get a couple of items we'll need later */ X bcopy((char*)info.dlen, (char*)hqx_datalen, 4); X *hqx_datalen = mac2long(*hqx_datalen); X bcopy((char*)info.rlen, (char*)hqx_rsrclen, 4); X *hqx_rsrclen = mac2long(*hqx_rsrclen); } X X /* This routine copies bytes from the decoded input stream to the output. X It also pads to a multiple of 128 bytes on the output, which is part X of the .bin format */ word hqx_to_bin_fork(nbytes) X register ulong nbytes; { X register byte *cp; X register ulong calc_crc; X register int c_length; X ulong extra_bytes; X extern word magic[]; X long avail = 0; /* used for internal consistency checking */ X int wrote; X X extra_bytes = 127 - (nbytes + 127) % 128; /* pad fork to mult of X * 128 bytes */ X calc_crc = 0; X for (;;) { X cp = buf_ptr; X c_length = (cp + nbytes > buf_end) ? buf_end - cp : nbytes; X /* we can only check readily if we read it here */ X if (avail && c_length > avail) X error("hqx_to_bin_fork: writing %ld too many bytes", X (char*)c_length - avail); X nbytes -= c_length; X wrote = fwrite((char*)cp, sizeof(byte), c_length, binfile); X if (wrote != c_length) X error("hqx_to_bin_fork: fwrite on binfile wrote %ld bytes too few", X (char*)c_length-wrote); X while (c_length--) X calc_crc = (((calc_crc & 0xff) << 8) | *cp++) ^ magic[calc_crc >> 8]; X if (!nbytes) X break; X avail = fill_hqxbuf(0); X } X buf_ptr = cp; X while (extra_bytes--) X if (EOF == putc(0, binfile)) X error("Error: putc failed on binfile", ""); X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8]; X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8]; X return (word) calc_crc; } X /* This routine copies bytes from the input stream to the encoded output. X It also pads to a multiple of 128 bytes on the input, which is part X of the .bin format */ word bin_to_hqx_fork(nbytes) X register ulong nbytes; { X register byte *cp; X register ulong calc_crc; X register int c_length; X ulong extra_bytes; X extern word magic[]; X X extra_bytes = 127 - (nbytes + 127) % 128; /* pad fork to mult of X * 128 bytes */ X calc_crc = 0; X for (;;) { X cp = buf_ptr; X c_length = (cp + nbytes > buf_end) ? buf_end - cp : nbytes; X nbytes -= c_length; X if (c_length != fread((char*)cp, sizeof(byte), c_length, binfile)) X error("fread failed on binfile", ""); X buf_ptr += c_length; X while (c_length--) X calc_crc = (((calc_crc & 0xff) << 8) | *cp++) ^ magic[calc_crc >> 8]; X if (!nbytes) X break; X empty_hqxbuf(); X } X buf_ptr = cp; X X fseek(binfile, (long)extra_bytes, 1); X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8]; X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8]; X return (word) calc_crc; } X /* Essentials for Binhex 8to6 run length encoding */ #define RUNCHAR 0x90 #define MAXRUN 255 #define IS_LEGAL <0x40 #define ISNT_LEGAL >0x3f #define DONE 0x7F /* tr68[':'] = DONE, since Binhex terminator is ':' */ #define SKIP 0x7E /* tr68['\n'|'\r'] = SKIP, i. e. end of line char. */ X /* We also treat '\0' as SKIP to handle files without trailing newline */ X X /* X NOTE: we really don't do a very good job of handling lines X with ^M's as the end of line character, since we jettison X the entire UNIX line (which can look like multiple Mac X lines) when rejecting the line. Easiest way to fix this is X to write our own version of fgets which breaks on ^M or ^J. X */ X #define FAIL 0x7D /* character illegal in binhex file */ X byte tr86[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; byte tr68[] = { /* 0x00 */ X SKIP, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, SKIP, FAIL, FAIL, SKIP, FAIL, FAIL, /* 0x10 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0x20 */ X FAIL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, X 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, FAIL, FAIL, /* 0x30 */ X 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, FAIL, X 0x14, 0x15, DONE, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0x40 */ X 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, X 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, FAIL, /* 0x50 */ X 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, FAIL, X 0x2C, 0x2D, 0x2E, 0x2F, FAIL, FAIL, FAIL, FAIL, /* 0x60 */ X 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, FAIL, X 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, FAIL, FAIL, /* 0x70 */ X 0x3D, 0x3E, 0x3F, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0x80 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0x90 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0xA0 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0xB0 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0xC0 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0xD0 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0xE0 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* 0xF0 */ X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, X FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, }; X /* X * This procedure transparently reads and decodes the hqx input. X * It does run length and 6 to 8 decoding. X * As many lines as required are read to fill up buf. X * Global Input X * buf_start X * line_ptr X * save_* X * Global Output X * buf_ptr end of buffer used X * line_ptr X * save_* X * Internal X * line holds the encoded incoming ascii line. X * buf holds the decoding binary binary. [what the heck does this mean?] X * buf[-1] holds the character to be repeated for run length encoding. X */ #define READING 0 #define SKIPPING 1 #define FIND_START_COLON 2 #define FINDING_COLON 3 X /* X X * It's too bad we can't look for ``(This file ..'' when hunting for a X * starting colon, but we don't emit such a line at the head of every X * segment, so we can't expect to find one, now, can we? X X * We were really too brittle when scanning, since we only X * accepted lines which were exactly 64 (HQXLINELEN) characters long. X * Fixed in version 1.83. But allowing any length valid line X * permitted the false-match-in-mail-headers-problem for lines like "---". X * Better header skipping provided in 1.84. X X * XXX: rather than decode line inplace, it would be better X * to leave the original intact to enable better warning messages X X */ X /* returns the number of bytes read */ fill_hqxbuf(same_file_only) X int same_file_only; { X register ulong c, accum; X register int not_in_a_run = TRUE, state68; X register byte *fast_buf, *fast_line; X static int phase = FIND_START_COLON; X long avail; X X buf_ptr = fast_buf = buf_start; X fast_line = line_ptr; X state68 = save_state; X accum = save_accum; X if (save_run_length > 0) { X c = save_run_length; X save_run_length = 0; X goto continue_run; X } X X while (fast_buf < buf_end) { X next_char: X if ((c = *fast_line++) ISNT_LEGAL) { X if (c == DONE) { X /* done processing the file, so get out */ X /* phase has already been set by read processing */ X break; X } X X next_line: X if (!fgets(LINE_START, MAXLINE, hqxfile)) { X if (same_file_only) { X avail = fast_buf - buf_ptr; X if (avail != 0) { X DEBUG && fprintf(debug, "DEBUG: avail: %d\n", avail); X DEBUG && fflush(debug); X error( X "Premature EOF reading non-initial BinHex 4.0 header from %s", X hqxfname); X } else { X /* this routine may be called many times in a row, X * and we must ensure that we don't allow fast_line X * to march beyond the end of line (it did), so we jam X * fast_line to the start of the line, and salt the X * line to mark it invalid, so a new line will be fetched. X * Jeepers, how I hate the (il)logic of this routine! X */ X fast_line = line_start; X *fast_line = SKIP; X break; X } X /*NOTREACHED*/ X } else if (new_in_hqx_file() == 0) { X /* X * Used to assume if no more input available through error or X * exhaustion while looking for valid data then must be done. X * But we are demand driven (now) and if called, must X * find data. So we don't silently exit any more. X */ X error("Premature EOF while reading BinHex 4.0 %s", hqxfname); X } X } X line_ptr = line_start; X X if (Debug > 1) { X fprintf(debug, "DEBUG: input: %s", line_start); X fflush(debug); X } X X scan_line: X X /* ensure the the entire line is valid */ X X fast_line = line_ptr; X while ((*fast_line = tr68[*fast_line]) IS_LEGAL) X fast_line++; X X /* grab the stopper */ X c = *fast_line; X X /* check for validity, transition phases as required */ X switch (phase) { X X case READING: X case SKIPPING: X case FINDING_COLON: X if (SKIP == c && fast_line > line_ptr && X ( 0 == hqxsuspect || X non_suspect((char *)line_ptr, (char *)fast_line) ) X ) { X /* the entire line is valid (again), so (resume) reading */ X /* hack: require the line to be non-empty to simplify logic */ X /* require line to non suspect [outside [mail] header] */ X phase = READING; X break; X } X if (c == DONE && tr68[fast_line[1]] == SKIP) { X /* X * valid encoded last line, so X * set phase for next line, and process this line -- X * we exit the fill-the-buffer loop when the terminal X * colon is encountered during line processing X */ X phase = FIND_START_COLON; X break; X } X X /* line is not entirely valid, so do some flavor of skipping */ X phase = (phase == FINDING_COLON) ? FIND_START_COLON : SKIPPING; X /* we're suspicious again, since we could be reading a X * concatenated multi-segmented file */ X hqxsuspect = 1; X goto next_line; X X case FIND_START_COLON: X if (*line_start == DONE) { X /* can't transition to READING X * until know that entire line is valid X * so transition to intermediate state X */ X phase = FINDING_COLON; X /* skip the initial colon */ X line_ptr++; X goto scan_line; X } X goto next_line; X X } X X /* we've read in a valid line, so start processing it */ X fast_line = line_ptr; X c = *fast_line++; X X /* X * Jskud 15Jul92: fix bug reported by Info-Mac Moderator Bill X * regarding case of last line just : X * The line is valid, but it has no data, so don't ingest it. X */ X X if (c == DONE) X break; X X if (Debug > 1) { X fprintf(debug, "DEBUG: processing above line\n\n"); X fflush(debug); X } X X } X X /* Finally, we have the next 6 bits worth of data in "c" as input. */ X /* Note: we use "c" as the output of this processing too */ X switch (state68++) { X case 0: X accum = c; X goto next_char; X case 1: X accum = (accum << 6) | c; X c = accum >> 4; X break; X case 2: X accum = (accum << 6) | c; X c = (accum >> 2) & 0xff; X break; X case 3: X /* we avoid any miniscule optimizations here X * to maintain parallelism and clarity X * which should enhance program maintainability X */ X accum = (accum << 6) | c; X c = accum & 0xff; X state68 = 0; X break; X } X if (not_in_a_run) X if (c != RUNCHAR) X *fast_buf++ = c; X else { X not_in_a_run = FALSE; X goto next_char; X } X else { X /* "c" has the run total length, not just the incremental, X hence the post decrement is correct */ X if (c--) { X avail = buf_end - fast_buf; X if (c > avail) { X save_run_length = c - avail; X c = avail; X } X continue_run: X { X register char ch = fast_buf[-1]; X X while (c--) X *fast_buf++ = ch; X } X X } else X /* handle special case of 0x9000 => 0x90 */ X *fast_buf++ = RUNCHAR; X X not_in_a_run = TRUE; X } X } X /* exit: */ X avail = fast_buf - buf_ptr; X total_bytes += avail; X buf_start[-1] = fast_buf[-1]; X line_ptr = fast_line; X save_state = state68; X save_accum = accum; X X return avail; X } X non_suspect(start, beyond) X char *start; X char *beyond; { X int looking_good; X int len; X register char *cp; X register char *last; X char *skip_msg = "Warning: skipping legal but suspect line in hqx file"; X X /* ensure it's long enough */ X len = beyond - start; X looking_good = len >= suspect_shorter; X DEBUG && fprintf(debug, "DEBUG: non_suspect: long enough: %d\n", X looking_good); X DEBUG && fflush(debug); X if (!looking_good) { X fprintf(verbose, "%s -- line too short (%d < %d)\n", X skip_msg, len, suspect_shorter); X fflush(verbose); X } X X /* ensure it's different enough */ X if (suspect_same && looking_good) { X last = beyond - 1; X for (cp = start; cp < last; cp++) X if (*cp != *last) { X break; X } X /* is different */ X looking_good = cp != last; X DEBUG && fprintf(debug, X "DEBUG: non_suspect: different enough: %d\n", X looking_good); X DEBUG && fflush(debug); X if (!looking_good) { X if (*last IS_LEGAL) { X fprintf(verbose, "%s -- all one input char ('%c')\n", X skip_msg, tr86[*last] ); X } else { X fprintf(verbose, "%s -- all chars mapped to 0x%02x\n", X skip_msg, *last ); X } X fflush(verbose); X } X } X X hqxsuspect = !looking_good; X X return looking_good; } X new_in_hqx_file() { X extern char **hqxnames_left; X int result; X long len; X X DEBUG && fprintf(debug, "entering new_in_hqx_file ...\n"); X DEBUG && fflush(debug); X X if (*hqxnames_left[0] == '\0' || *hqxnames_left[0] == '-') { X result = FALSE; X goto exit; X } X X len = strlen(*hqxnames_left); X if (len >= sizeof(hqxfname)) X error("Error: specified hqxfname is too long", ""); X strcpy(hqxfname, *hqxnames_left++); X /* X * we used to use freopen, X * but now suffer the slight inefficiency of close/open X * to provide info_only and consistent handling X * with good software engineering methods X */ X mclose(&hqxfile, "hqxfile"); X hqxfile = mopen(hqxfname, ".hqx", "r"); X hqxsuspect = 1; X (void)fgets(LINE_START, MAXLINE, hqxfile); X result = TRUE; X exit: X if (result == TRUE) X DEBUG && fprintf(debug, "... opened %s\n", hqxfname); X else X DEBUG && fprintf(debug, "... nothing to open\n"); X DEBUG && fflush(debug); X X return result; } X /* X * This procedure transparently encodes and writes the hqx output. X * It does run length and 8 to 6 encoding. X */ empty_hqxbuf() { X register ulong c, accum, last_c; X register byte *fast_buf, *fast_line; X register int state86, dont_look_for_runs = FALSE, run_length; X extern int maxlines; X X run_length = save_run_length; X last_c = buf_start[-1]; X fast_buf = buf_start; X fast_line = line_ptr; X state86 = save_state; X accum = save_accum; X while (fast_buf < buf_ptr) { X c = *fast_buf++; X if (dont_look_for_runs) X dont_look_for_runs = FALSE; X else if (last_c == c && run_length < MAXRUN) { X run_length++; X continue; X } else { X if (run_length > 1) { X --fast_buf; X if (run_length == 2 && last_c != RUNCHAR) X c = last_c; X else { X c = RUNCHAR; X *--fast_buf = run_length; X dont_look_for_runs = TRUE; X } X run_length = 1; X } else X last_c = c; X if (c == RUNCHAR && !dont_look_for_runs) { X *--fast_buf = 0; X dont_look_for_runs = TRUE; X } X } X X if (fast_line == line_end) { X if (line_count++ == maxlines) X new_out_hqx_file(); X fputs(LINE_START, hqxfile); X fast_line = line_start; X } X switch (state86++) { X case 0: X *fast_line++ = tr86[c >> 2]; X accum = (c << 4) & 0x3f; X break; X case 1: X *fast_line++ = tr86[(c >> 4) | accum]; X accum = (c << 2) & 0x3f; X break; X case 2: X *fast_line++ = tr86[(c >> 6) | accum]; X if (fast_line == line_end) { X if (line_count++ == maxlines) X new_out_hqx_file(); X fputs(LINE_START, hqxfile); X fast_line = line_start; X } X *fast_line++ = tr86[c & 0x3f]; X state86 = 0; X break; X } X } X save_run_length = run_length; X buf_start[-1] = last_c; X buf_ptr = buf_start; X line_ptr = fast_line; X save_state = state86; X save_accum = accum; } X new_out_hqx_file() { X char filename[SYSNAMELEN + 7]; X extern int maxlines; X X fprintf(hqxfile, "<<< End of Part %2d >>>\n", file_count); X mclose(&hqxfile, "hqxfile"); X file_count++; X if (maxlines) X sprintf(filename, "%s%02d.hqx", hqxfname, file_count); X else X sprintf(filename, "%s.hqx", hqxfname); X hqxfile = mopen(filename, "", "w"); X if (file_count > 1) X fprintf(hqxfile, "<<< Start of Part %2d >>>\n", file_count); X else X fprintf(hqxfile, "(This file must be converted with BinHex 4.0)\n\n"); X line_count = 3; } X check_hqx_crc(calc_crc, msg, name) X word calc_crc; X char msg[], name[]; X { X word read_crc; X X if (buf_ptr >= buf_end) X (void)fill_hqxbuf(0); X read_crc = *buf_ptr++ << 8; X if (buf_ptr >= buf_end) X (void)fill_hqxbuf(0); X read_crc |= *buf_ptr++; X if (read_crc != calc_crc) X error(msg, name); } X write_hqx_crc(calc_crc) X word calc_crc; { X if (buf_ptr == buf_end) X empty_hqxbuf(); X *buf_ptr++ = calc_crc >> 8; X if (buf_ptr == buf_end) X empty_hqxbuf(); X *buf_ptr++ = calc_crc; } X un_hqx(unpit_flag) X int unpit_flag; { X char type[5]; /* stuff EOS */ X ulong hqx_datalen, hqx_rsrclen; X word un_pit(); X int unpitting, bytes_read; X word calc_crc; X extern char **hqxnames_left; X int same_file_only = 0; X int active; X X /* we read EOF on this to transision, so the stream must be valid */ X hqxfile = devnull; X line_end = line_start + HQXLINELEN; X buf_end = buf_start + HQXBUFLEN; X X while (1) { X total_bytes = 0; X line_ptr = line_start; X /* ensure that the line buffer is considered empty */ X /* why we use SKIP and not newline, I'm not sure */ X line_ptr[0] = SKIP; X save_state = 0; X save_run_length = 0; X X active = hqx_to_bin_hdr(type, &hqx_datalen, &hqx_rsrclen, same_file_only); X if (active == 0) X break; X same_file_only = 1; X type[4] = 0; /* set EOS */ X X unpitting = unpit_flag && !strcmp(type, "PIT "); X DEBUG && fprintf(debug, X "DEBUG: unpit_flag=%d type=%s unpitting=%d\n", X unpit_flag, type, unpitting); X DEBUG && fflush(debug); X if (unpitting) { X mclose(&binfile, "binfile"); X /* Do not unlink files we did not open */ X if (!info_only) X unlink(binfname); X bytes_read = total_bytes - (buf_end - buf_ptr); X calc_crc = un_pit(); X bytes_read = total_bytes - (buf_end - buf_ptr) - bytes_read; X if (bytes_read != hqx_datalen) { X fprintf(verbose, X "Warning - Extraneous characters ignored in %s\n", binfname); X fflush(verbose); X } X } else { X calc_crc = hqx_to_bin_fork(hqx_datalen); X } X check_hqx_crc(calc_crc, "File data CRC mismatch in %s", binfname); X X calc_crc = hqx_to_bin_fork(hqx_rsrclen); X check_hqx_crc(calc_crc, "File rsrc CRC mismatch in %s", binfname); X X if (!unpitting) { X mclose(&binfile, "binfile"); X } X X } X mclose(&hqxfile, "hqxfile"); } X re_hqx() { X word calc_crc; X ulong hqx_datalen, hqx_rsrclen; X extern char **hqxnames_left; X extern int maxlines; X X line_end = line_start + HQXLINELEN; X buf_end = buf_start + HQXBUFLEN; X while (*hqxnames_left[0] != '-') { X /* we write the trailer, so the stream must be valid */ X hqxfile = devnull; X X /* X * We use the trick of setting our line_count at the limit to X * force an immediate transition on overflow. X */ X line_count = maxlines; X X file_count = 0; X line_ptr = line_start; X *line_ptr++ = ':'; X strcpy((char*)line_end, "\n"); X buf_ptr = buf_start; X save_state = 0; X save_run_length = 1; X X bin_to_hqx_hdr(&hqx_datalen, &hqx_rsrclen); /* calculates hqxfname */ X X /* X * Now that we have hqxfname, start the new file if X * not yet started. We no longer wait until the output X * buffer overflows, since empty files with short names didn't overflow! X */ X X if (file_count == 0) X new_out_hqx_file(); X X calc_crc = bin_to_hqx_fork(hqx_datalen); X write_hqx_crc(calc_crc); X X calc_crc = bin_to_hqx_fork(hqx_rsrclen); X write_hqx_crc(calc_crc); X /* X * To end a run and to get the last stray bits, X * temporarily add a char. X */ X *buf_ptr = !buf_ptr[-1]; X buf_ptr++; X empty_hqxbuf(); X /* now toss any extra output character generated */ X if (save_state != 2) X --line_ptr; X X /* if we're at the end of the line now, write it out */ X if (line_ptr == line_end) { X fputs(LINE_START, hqxfile); X line_ptr = line_start; X } X X /* paste the trailing colon onto the end of the line */ X /* recall that line_ptr points into the line, not at the line */ X strcpy((char*)line_ptr, ":\n"); X X /* and flush the output buffer */ X fputs(LINE_START, hqxfile); X X mclose(&hqxfile, "hqxfile"); X mclose(&binfile, "binfile"); X X } } X SHAR_EOF chmod 0444 hqxify.c || echo 'restore of hqxify.c failed' Wc_c="`wc -c < 'hqxify.c'`" test 28332 -eq "$Wc_c" || echo 'hqxify.c: original size 28332, current size' "$Wc_c" fi # ============= unpack.c ============== if test -f 'unpack.c' -a X"$1" != X"-c"; then echo 'x - skipping unpack.c (File already exists)' else echo 'x - extracting unpack.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'unpack.c' && #include "mactypes.h" X extern word magic[]; extern char *dir, *ext; extern int info_only; X ulong pit_datalen, pit_rsrclen; word hqx_crc, write_pit_fork(); char pitfname[SYSNAMELEN]; /* name of file being unpacked */ FILE *pitfile; /* output file */ X branch branchlist[255], *branchptr, *read_tree(); leaf leaflist[256], *leafptr; word Huff_nibble, Huff_bit_count; X byte(*read_char) (), get_crc_byte(), getHuffbyte(); X word un_pit() { X char PitId[4]; X int i; X word pit_crc; X X hqx_crc = 0; X /* Read and unpack until the PackIt End message is read */ X for (;;) { X read_char = get_crc_byte; X for (i = 0; i < 4; i++) X PitId[i] = (char) get_crc_byte(); X if (!strncmp(PitId, "PEnd", 4)) X break; X X if (strncmp(PitId, "PMag", 4) && strncmp(PitId, "PMa4", 4)) X error("Unrecognized Packit format message %s", PitId); X X if (PitId[3] == '4') { X /* if this file is compressed */ X /* read the Huffman decoding */ X /* tree that is on the input */ X /* and use Huffman decoding */ X /* subsequently */ X branchptr = branchlist; X leafptr = leaflist; X Huff_bit_count = 0; X (void)read_tree(); X read_char = getHuffbyte; X } X read_pit_hdr(); /* also calculates datalen, X * rsrclen, pitfile, pitfname */ X pit_crc = write_pit_fork(pit_datalen, (ulong)0); X pit_crc = write_pit_fork(pit_rsrclen, (ulong)pit_crc); X check_pit_crc(pit_crc, " File data/rsrc CRC mismatch in %s", pitfname); X mclose(&pitfile, "pitfile"); X } X hqx_crc = (hqx_crc << 8) ^ magic[hqx_crc >> 8]; X hqx_crc = (hqx_crc << 8) ^ magic[hqx_crc >> 8]; X return hqx_crc; } X check_pit_crc(calc_crc, msg, name) X word calc_crc; X char msg[], name[]; X { X word read_crc; X X read_crc = (*read_char) () << 8; X read_crc |= (*read_char) (); X if (read_crc != calc_crc) X error(msg, name); } X /* X * This routine reads the header of a packed file and appropriately X * twiddles it, determines if it has CRC problems, creates the .bin X * file, and puts the info into the .bin file. Output is X * pit_datalen, pit_rsrclen, pitfname, pitfile X */ read_pit_hdr() { X register int n; X register byte *pit_byte; X register ulong pit_crc; X pit_header pit; X info_header info; X short crc; X char *action; X long len; X X extern short calc_mb_crc(); X X /* read the pit header and compute the CRC */ X pit_crc = 0; X pit_byte = (byte *) & pit; X for (n = 0; n < sizeof(pit_header); n++) { X *pit_byte = (*read_char) (); X pit_crc = ((pit_crc & 0xff) << 8) X ^ magic[*pit_byte++ ^ (pit_crc >> 8)]; X } X X /* stuff the pit header data into the info header */ X bzero((char*)&info, sizeof(info_header)); X info.nlen = pit.nlen; X if (pit.nlen > sizeof(info.name)) X error("Error: corrupt PIT data format", ""); X /* X * expect a valid Macintosh file name since it came from a PIT file X * and don't potentially corrupt a valid copied name via macify X */ X strncpy((char*)info.name, (char*)pit.name, (int)pit.nlen);/* name */ X bcopy((char*)pit.type, (char*)info.type, 9); /* type, author, flag */ X bcopy((char*)pit.dlen, (char*)info.dlen, 16); /* (d,r)len, (c,m)tim */ X info.flags &= 0x7e; /* reset lock bit, init bit */ X if (pit.protect & 0x40) X info.protect = 1; /* copy protect bit */ X info.uploadvers = '\201'; X info.readvers = '\201'; X X /* calculate MacBinary CRC */ X crc = calc_mb_crc((unsigned char*)&info, 124L, 0); X info.crc[0] = (char) (crc >> 8); X info.crc[1] = (char) crc; X X /* Create the .bin file and write the info to it */ X pit.name[pit.nlen] = '\0'; X unixify((char*)pit.name); X X len = strlen(dir) + strlen((char*)pit.name) + strlen(ext) + 1; X if (len >= sizeof(pitfname)) X error("Error: generated pitfname would be too long", ""); X sprintf(pitfname, "%s/%s%s", dir, pit.name, ext); X X if (info_only) X action = (read_char == get_crc_byte) ? "Packed" : "Compressed"; X else X action = (read_char == get_crc_byte) ? "Unpacking" : "Decompressing"; X X fprintf(convert, " %-14s%-30s type = \"%4.4s\", author = \"%4.4s\"\n", X action, pit.name, pit.type, pit.auth); X fflush(convert); X print_bin_hdr("Creating", &info); X pitfile = mopen(pitfname, "", "w"); X check_pit_crc((word)pit_crc, " File header CRC mismatch in %s", pitfname); X if (1 != fwrite((char*)&info, sizeof(info_header), 1, pitfile)) X error("fwrite failed on pitfile", ""); X X /* Get a couple of items we'll need later */ X bcopy((char*)pit.dlen, (char*)&pit_datalen, 4); X pit_datalen = mac2long(pit_datalen); X bcopy((char*)pit.rlen, (char*)&pit_rsrclen, 4); X pit_rsrclen = mac2long(pit_rsrclen); } X /* This routine copies bytes from the decoded input stream to the output X and calculates the CRC. It also pads to a multiple of 128 bytes on the X output, which is part of the .bin format */ word write_pit_fork(nbytes, calc_crc) X register ulong nbytes; X register ulong calc_crc; { X register ulong b; X int extra_bytes; X X /* pad fork to mult of * 128 bytes */ X extra_bytes = 127 - (nbytes + 127) % 128; X while (nbytes--) { X b = (*read_char) (); X calc_crc = ((calc_crc & 0xff) << 8) ^ magic[b ^ (calc_crc >> 8)]; X if (EOF == putc((char)b, pitfile)) X error("Error: putc failed on pitfile", ""); X } X while (extra_bytes--) X if (EOF == putc(0, pitfile)) X error("Error: putc failed on pitfile", ""); X return (word) calc_crc; } X /* This routine recursively reads the compression decoding data. X It appears to be Huffman compression. Every leaf is represented X by a 1 bit, then the byte it represents. A branch is represented X by a 0 bit, then its zero and one sons */ branch * read_tree() { X register branch *branchp; X register leaf *leafp; X register ulong b; X X if (!Huff_bit_count--) { X Huff_nibble = get_crc_byte(); X Huff_bit_count = 7; X } X if ((Huff_nibble <<= 1) & 0x0100) { X leafp = leafptr++; X leafp->flag = 1; X b = get_crc_byte(); X leafp->data = Huff_nibble | (b >> Huff_bit_count); X Huff_nibble = b << (8 - Huff_bit_count); X return (branch *) leafp; X } else { X branchp = branchptr++; X branchp->flag = 0; X branchp->zero = read_tree(); X branchp->one = read_tree(); X return branchp; X } } X /* This routine returns the next 8 bits. It finds the byte in the X Huffman decoding tree based on the bits from the input stream. */ byte getHuffbyte() { X register branch *branchp; X X branchp = branchlist; X while (!branchp->flag) { X if (!Huff_bit_count--) { X Huff_nibble = get_crc_byte(); X Huff_bit_count = 7; X } X branchp = ((Huff_nibble <<= 1) & 0x0100) ? branchp->one : branchp->zero; X } X return ((leaf *) branchp)->data; } X /* This routine returns the next byte on the .hqx input stream, hiding X most file system details at a lower level. .hqx CRC is maintained X here */ byte get_crc_byte() { X register ulong c; X extern byte *buf_ptr, *buf_end; X X if (buf_ptr == buf_end) { X if (fill_hqxbuf(0) == 0) X error("premature EOF reading PIT info from BinHex 4.0 file", ""); X } X c = *buf_ptr++; X hqx_crc = ((hqx_crc << 8) | c) ^ magic[hqx_crc >> 8]; X return (byte) c; } SHAR_EOF chmod 0444 unpack.c || echo 'restore of unpack.c failed' Wc_c="`wc -c < 'unpack.c'`" test 6868 -eq "$Wc_c" || echo 'unpack.c: original size 6868, current size' "$Wc_c" fi # ============= mactypes.h ============== if test -f 'mactypes.h' -a X"$1" != X"-c"; then echo 'x - skipping mactypes.h (File already exists)' else echo 'x - extracting mactypes.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'mactypes.h' && #include <stdio.h> #include <sys/types.h> #include <sys/dir.h> #include <sys/stat.h> X #ifdef TIMEVAL # include <sys/param.h> # include <sys/time.h> #else # include <sys/timeb.h> #endif X typedef unsigned char byte; /* one byte, obviously */ typedef unsigned short word; /* must be 2 bytes */ #ifndef ULONG X typedef unsigned long ulong; /* 4 bytes */ #endif X /* declarations to keep lint informed */ char *calloc(); #include <string.h> void exit(); #ifndef __osf__ long time(); #endif ulong unix2mac(); ulong mac2unix(); char *ctime(); FILE *mopen(); X #define TRUE 1 #define FALSE 0 #define CR 0x0d #define LF 0x0a X /* various files and debug options */ extern FILE *devnull; /* constant /dev/null for bit bucket output */ extern FILE *convert; /* convert messages */ extern FILE *verbose; /* verbose output */ extern FILE *debug; /* debug output */ extern int Debug; /* debug level */ #define DEBUG (debug != devnull) X /* Compatibility issues */ X #ifdef NOBYTEORDER #define mac2word #define mac2long #define word2mac #define long2mac #else #include <netinet/in.h> #define mac2word (word) ntohs #define mac2long (ulong) ntohl #define word2mac (word) htons #define long2mac (ulong) htonl #endif X #ifdef NOBZEROBCOPY #define bzero(dst,len) (memset(dst,0,len)) #define bcopy(src,dst,len) (memcpy(dst,src,len)) #endif X #define MAXEXTENSION 5 /* max(".bin", ".text", ".data", ".rsrc") */ #define SYSNAMELEN 1024 /* reasonable UNIX working name length */ #define NAMELEN 63 /* maximum legal Mac file name length */ X /* Format of a bin file: A bin file is composed of 128 byte blocks. The first block is the info_header (see below). Then comes the data fork, null padded to fill the last block. Then comes the resource fork, padded to fill the last block. A proposal to follow with the text of the Get Info box has not been implemented, to the best of my knowledge. Version, zero1 and zero2 are what the receiving program looks at to determine if a MacBinary transfer is being initiated. */ X /* info file header (128 bytes) */ typedef struct { X /* Unfortunately, the longs don't align to word boundaries */ X /* decimal offset */ X /* 000 */ X byte version; /* there is only a version 0 at this time */ /* 001 */ X byte nlen; /* Length of filename. */ /* 002 */ X byte name[NAMELEN]; /* Filename (only 1st nlen are significant) */ /* 065 */ X byte type[4]; /* File type. */ /* 069 */ X byte auth[4]; /* File creator. */ /* 073 */ X byte flags; /* file flags: LkIvBnSyBzByChIt */ X /* Locked, Invisible,Bundle, System */ X /* Bozo, Busy, Changed, Init */ /* 074 */ X byte zero1; /* 075 */ X byte icon_vert[2]; /* Vertical icon position within window */ /* 077 */ X byte icon_horiz[2]; /* Horizontal icon postion in window */ /* 079 */ X byte window_id[2]; /* Window or folder ID. */ /* 081 */ X byte protect; /* = 1 for protected file, 0 otherwise */ /* 082 */ X byte zero2; /* 083 */ X byte dlen[4]; /* Data Fork length (bytes) - most sig. */ /* 087 */ X byte rlen[4]; /* Resource Fork length byte first */ /* 091 */ X byte ctim[4]; /* File's creation date. */ /* 095 */ X byte mtim[4]; /* File's "last modified" date. */ /* 099 */ X byte ilen[2]; /* GetInfo message length */ /* 101 */ X byte flags2; /* Finder flags, bits 0-7 */ /* 102 */ X byte unused[14]; /* 116 */ X byte packlen[4]; /* length of total files when unpacked */ /* 120 */ X byte headlen[2]; /* length of secondary header */ /* 122 */ X byte uploadvers; /* Version of MacBinary II that the uploading X * program is written for */ /* 123 */ X byte readvers; /* Minimum MacBinary II version needed to read X * this file */ /* 124 */ X byte crc[2]; /* CRC of the previous 124 bytes */ /* 126 */ X byte padding[2]; /* two trailing unused bytes */ /* 128 */ } info_header; X /* The *.info file of a MacTerminal file transfer either has exactly this structure or has the protect bit in bit 6 (near the sign bit) of byte zero1. The code I have for macbin suggests the difference, but I'm not so sure */ X /* X * Format of a hqx file: X * (but see also binhex-40-specs.txt for legal variations) X * X * It begins with a line that begins "(This file" and the rest is 64 X * character lines (except possibly the last, and not including X * newlines) where the first begins and the last ends with a colon. X * The characters between colons should be only from the set in tr86, X * below, each of which corresponds to 6 bits of data. Once that is X * translated to 8 bit bytes, you have the real data, except that the X * byte 0x90 may indicate, if the following character is nonzero, that X * the previous byte is to be repeated 1 to 255 times all together X * (that is, the count following 0x90 contains the total run length, X * not the marginal repeat count). The byte 0x90 is represented by X * 0x9000. The information in the file is the hqx_buf (see below), a X * CRC word, the data fork, a CRC word, the resource fork, and a CRC X * word. There is considerable confusion about the flags. An X * official looking document unclearly states that the init bit is X * always clear, as is the following byte. The experience of others X * suggests, however, that this is not the case. X */ X /* NOTE: X * Jskud 25Jun92 X X * a hqx file has no date/time information, and a binary constructed X * from a hqx file will use the current time; therefore, reconverting X * a hqx file repeatedly will generate different bin files! X X * The "flags" byte can change when refetched, for example, whether or X * not the init bit is set (that is, the Finder has "seen" the file); X * this can affect the hqx file, including the run length encoding, so X * the hqx files can look quite different, although the actual X * difference is miniscule; also, the init bit difference will not be X * present when the hqx file is converted to a bin file, since both the X * locked and init bits are cleared on bin file creation. X X * Because we've experienced this "spurious" difference, and since X * the init bit is only thought meaningful when running on the Mac, X * and to establish symmetry between bin file creation and hqx file X * creation, we unconditionally clear the init and locked bits when X * creating the hqx file. X X */ X #define HQXLINELEN 64 typedef struct { /* decimal offset */ /* 000 */ X byte version; /* there is only a version 0 at this time */ /* 001 */ X byte type[4]; /* File type. */ /* 005 */ X byte auth[4]; /* File creator. */ /* 009 */ X byte flags; /* file flags: LkIvBnSyBzByChIt */ /* 010 */ X byte protect; /* ?Pr??????, don't know what ? bits mean */ /* 011 */ X byte dlen[4]; /* Data Fork length (bytes) - most sig. */ /* 015 */ X byte rlen[4]; /* Resource Fork length byte first */ /* 019 */ X byte bugblank; /* to fix obscure sun 3/60 problem that always X * makes sizeof(hqx_header) even */ /* 020 */ } hqx_header; X /* hqx file header buffer (includes file name) */ typedef struct { X byte nlen; /* Length of filename. */ X byte name[NAMELEN]; /* Filename: only nlen actually appear */ X hqx_header all_the_rest;/* and all the rest follows immediately */ } hqx_buf; X /* every valid hqx header is at least this long */ #define MIN_HQX_HDR (sizeof(hqx_header) + 2) X /* X * The minimum number of hqx_lines in a file to ensure that we have X * enough lines to emit the entire header before starting a new file. X * + 1 is for rounding, + 2 is for "(This file " and the blank line. X */ #define MIN_HQX_LINES (sizeof(hqx_buf) * 4 / 3 / HQXLINELEN + 1 + 2) X X /* Format of a Packit file: Repeat the following sequence for each file in the Packit file: X 4 byte identifier ("PMag" = not compressed, "Pma4" = compressed) X 320 byte compression data (if compressed file) X = preorder transversal of Huffman tree X 255 0 bits corresponding to nonleaf nodes X 256 1 bits corresponding to leaf nodes X 256 bytes associating leaf nodes with bytes X 1 completely wasted bit X 92 byte header (see pit_header below) * X 2 bytes CRC word for header * X data fork (length from header) * X resource fork (length from header) * X 2 bytes CRC word for forks * X Last file is followed by the 4 byte Ascii string, "Pend", and then the EOF. The CRC calculations differ from those in the binhex format. X * these are in compressed form if compression is on for the file X */ X typedef struct { /* Packit file header (92 bytes) */ X byte nlen; /* Length of filename. */ X byte name[NAMELEN]; /* Filename (only 1st nlen are significant) */ X byte type[4]; /* File type. */ X byte auth[4]; /* File creator. */ X byte flags; /* file flags: LkIvBnSyBzByChIt */ X byte zero1; X byte protect; /* = 1 for protected file, 0 otherwise */ X byte zero2; X byte dlen[4]; /* Data Fork length (bytes) - most sig. */ X byte rlen[4]; /* Resource Fork length byte first */ X byte ctim[4]; /* File's creation date. */ X byte mtim[4]; /* File's "last modified" date. */ } pit_header; X /* types for constructing the Huffman tree */ typedef struct branch_st { X byte flag; X struct branch_st *one, *zero; } branch; X typedef struct leaf_st { X byte flag; X byte data; } leaf; SHAR_EOF chmod 0444 mactypes.h || echo 'restore of mactypes.h failed' Wc_c="`wc -c < 'mactypes.h'`" test 9979 -eq "$Wc_c" || echo 'mactypes.h: original size 9979, current size' "$Wc_c" fi # ============= Makefile ============== if test -f 'Makefile' -a X"$1" != X"-c"; then echo 'x - skipping Makefile (File already exists)' else echo 'x - extracting Makefile (Text)' sed 's/^X//' << 'SHAR_EOF' > 'Makefile' && ## This file is formatted with a tab-width of 3 X ## See the README file for hints how to configure this Makefile. X CSOURCES = mcvert.c hqxify.c unpack.c HSOURCES = mactypes.h SOURCES = $(CSOURCES) $(HSOURCES) \ X Makefile README README-conversion mcvert.idraw mcvert.1 MANIFEST = $(SOURCES) mcvert.man OBJECTS = mcvert.o hqxify.o unpack.o $(XOBJ) ALL = mcvert mcvert.man EVERYTHING = $(ALL) shar mcvert.ps CLEAN = $(OBJECTS) $(EVERYTHING) X VERSION=216 X BIN = . X ## ## *LAST* Defintion Always Wins ## ## X ## Note: when using -lnet, AT&T 3B2 fails with undefined symbols like ## t_errno first used in /usr/lib/libnet.a ## so extract gettod.o and explicitly bind it in X ### Extra Objects # for AT&T 3B2 XXOBJ= gettod.o # common case XXOBJ= X ### Bind Time Library Selection # for SCO UNIX 3.2v4.1 with SCO TCPIP 1.2.0 LIBS= -lsocket # for most implementations LIBS= X ## Note that ftime() is obsolete, and has been replaced by gettimeofday() ## so, in general, you should be using -DTIMEVAL ## but I am not able to test this on all platforms on all releases, ## so we leave the aging recipe in place X ### Machine CFLAGS ## for machines with <timeb.h> and ftime() [and maybe without gettimeofday()] # eg: works for ULTRIX CFLAGS_M= ## for machines with ulong pre-defined CFLAGS_M= -DULONG # eg: A/UX, SGI's Irix, AT&T 3B2, IBM RS/6000's AIX CFLAGS_M= -DTIMEVAL -DULONG ## for machines with gettimeofday() [and maybe without <timeb.h> and ftime()] # eg: HP-UX 9.01, SunOS 4.1.3, DomainOS 10.4 CFLAGS_M= -DTIMEVAL X ### Byteorder(3n) [eg: htonl()] and Byte Manipulation [eg: bzero, bcopy] CFLAGS # uncommon case -- without support, eg: AT&T 3B2 CFLAGS_N = -DNOBYTEORDER -DNOBZEROBCOPY # unknown case 1 CFLAGS_N = -DNOBYTEORDER # unknown case 2 CFLAGS_N = -DNOBZEROBCOPY # common case -- with support for both CFLAGS_N = X ### Debugging/Optimization CFLAGS # debugging CFLAGS_D = -g # optimization CFLAGS_D = -O X ### All CFLAGS CFLAGS=$(CFLAGS_M) $(CFLAGS_N) $(CFLAGS_D) -DVERSION=$(VERSION) X ### lint related LINT=lint LFLAGS=$(CFLAGS_M) $(CFLAGS_N) -DVERSION=$(VERSION) X all: $(ALL) everything: $(EVERYTHING) X mcvert: $(OBJECTS) X $(CC) $(CFLAGS) $(OBJECTS) $(LIBS) -o $(BIN)/mcvert X lint: $(HSOURCES) $(CSOURCES) X $(LINT) $(LFLAGS) $(CSOURCES) | fgrep -vf lint-ignore X $(SOURCES): X sccs get $@ X gettod.o: X ar -xv /usr/lib/libnet.a $@ X $(OBJECTS): mactypes.h Makefile X shar : mcvert-$(VERSION).shar mcvert-$(VERSION).shar : $(MANIFEST) X shar $(MANIFEST) > $@ X @nawk 'length($0) > 80 {exit(1)}' $@ || { make check_linelen; false; } X # we punt the issue of expanding tabs check_linelen: $(MANIFEST) X @nawk 'length($0) >= 80 { printf "%s: %d: ", FILENAME, FNR; print }' \ X $(MANIFEST) X clean: X rm -f $(CLEAN) X man: mcvert.man mcvert.man: mcvert.1 X nroff -man mcvert.1 | col | sed 's/.//g' | expand > $@ mcvert.ps: mcvert.1 X groff -man mcvert.1 > $@ X F=mcvert-$(VERSION).shar info: X @for todo in "ls -l" "head -3" "tail -3" sum wc; do \ X echo $$todo $F; $$todo $F | sed 's/^/ /'; done SHAR_EOF chmod 0444 Makefile || echo 'restore of Makefile failed' Wc_c="`wc -c < 'Makefile'`" test 3030 -eq "$Wc_c" || echo 'Makefile: original size 3030, current size' "$Wc_c" fi # ============= README ============== if test -f 'README' -a X"$1" != X"-c"; then echo 'x - skipping README (File already exists)' else echo 'x - extracting README (Text)' sed 's/^X//' << 'SHAR_EOF' > 'README' && X mcvert comes in source form and runs on a wide variety of UNIX X machines, each with its own binary format and execution environment X for programs. Therefore, mcvert needs to be compiled for your X machine before you can run it. Here's how to do it. X o Ready a directory to hold mcvert X X cd X mkdir mcvert X cp mcvert-nnn.shar mcvert X cd mcvert X o Create the individual files from the Shell Archive (shar) file X X sh mcvert-nnn.shar X o Reorder the Makefile as appropriate for your machine X X Note that there are a number of variables with which to fiddle, X and that the last definition wins. X X For example, when compiling for AT&T's 3B2, reorder so these lines X are last within each group: X X XOBJ= gettod.o X X LIBS= X X CFLAGS_M= -DTIMEVAL -DULONG X X CFLAGS_N = -DNOBYTEORDER -DNOBZEROBCOPY X o Make the binary and the man page X X make X o Read the man page for a full description X X more mcvert.man X o Invoke the binary without arguments for a short description X X mcvert X [] SHAR_EOF chmod 0444 README || echo 'restore of README failed' Wc_c="`wc -c < 'README'`" test 1008 -eq "$Wc_c" || echo 'README: original size 1008, current size' "$Wc_c" fi # ============= README-conversion ============== if test -f 'README-conversion' -a X"$1" != X"-c"; then echo 'x - skipping README-conversion (File already exists)' else echo 'x - extracting README-conversion (Text)' sed 's/^X//' << 'SHAR_EOF' > 'README-conversion' && Overview of file conversion X More details regarding file formats may be found in the mcvert.1 man page, but basically, there are native Mac files that live (only) on the Mac (since they have interesting internal structure), and representations of Mac files. X One very important representation is called MacBinary. It is nothing but "data". But it is 8-bit data, and that confuses some things some times, like mail programs and modems. So, there are encodings of MacBinary files as ASCII only files, and one very important one is called BinHex4.0. So far, so good. X mcvert runs under UNIX and converts between different representations of Mac files. One very common conversion is between BinHex4.0 and MacBinary. So know we know how to do that (on a UNIX box). On the Mac, I prefer the CompactPro shareware for doing this conversion X A MacBinary file must be converted into the actual native Mac file it represents. One such program, which runs on the Mac, is binhex4.0. Often, though, programs like telnet from NCSA, kermit, White Knight, or any number of other communication programs will convert MacBinary files into the native Mac files they represent during transfer. X Files can be very large, and rather redundent. So it makes sense to compress the files to save space and reduce transfer cost. There are compressed file formats. Two popular ones are StuffIt and CompactPro. But if a file is compressed, something must uncompress it. There are unstuffers and extractors, which are separate programs which work on the compressed files. Some files are "self-extracting", which means the files are actually Mac programs which, when run, recreate the original file. X Files are often identified by extensions, those .ext suffixes at the end of the name. Common suffixes include: X X .bin MacBinary X .sit StuffIt X .cpt CompactPro X .hqx BinHex4.0 X .sea self extracting archive X It is not uncommon for multiple transformations to be applied, so if one had a file called foo.sit.bin, that likely means that it's a MacBinary format of a StuffIt archive file. So, to convert it, you must turn the MacBinary file into a native Mac file, and then run [un]StuffIt (or CompactPro, which can handle many StuffIt formats). X There's more information in the info-mac archives about getting files. For example, here's info-mac/help/accessing-files.txt, as of 13Jun93: X >------ Begin Included Message ------ > To access binaries in the Info-Mac archive at sumex-aim, use your > machine's ftp program. Type "ftp sumex-aim.stanford.edu". Use the > account name "anonymous" (lower-case) and enter any password. Then > "cd info-mac" to enter our directory. You should be able to transfer > binaries with a statement like "get app/silly-paint.hqx". > > NOTE: Almost all files (even binaries) in the Info-Mac archive are in > text format, even though they may not be human-readable. Hence, a FTP > transfer using a text-only option, often called ASCII, should work in > all common cases. > > In order to provide a reasonable level of performance and avoid > causing Internet overload, there is a 35-user limit for anonymous ftp > into sumex-aim during working hours, which we define as 8AM to 5PM > Pacific time, Monday through Friday. When sumex is busy, use one of > the many mirror archives around the world (see info/comm/ for a list > of other archive sites, including sumex mirrors.) Gopher is another > alternative; as a more modern alternative to ftp, it imposes less of a > burden on sumex, so there is no user limit. > > Here are some simple commands to move you around the directory structure. > This example assumes that you started in the /info-mac directory. > cd app # move into the app directory > ls # list the files there > get planet.hqx # transfer a file to your computer > cd .. # move back up to the parent directory > cd help # and so on... > > Most Info-Mac files are stored in BinHex 4.0 format. We have adopted > the common practice of labeling such files with .hqx extensions. To > take these files and use them on your Macintosh, you must first run > them through a program which will convert them from .hqx format into a > regular Macintosh file. On Unix systems, you can use the mcvert > program, stored as cmp/mcvert.shar. You can also do the conversion on > your Macintosh by using any of a number of utilities, including BinHex > 4.0, StuffIt, or Compact Pro. We recommend using Compact Pro because > it is slightly more convenient and reliable than the other tools. > Note: do NOT use BinHex 5.0 as it is incompatible, for some very > brain-damaged reasons. > > Note that some of our files were split into smaller pieces so that > they could be mailed more easily. Most such files are old, as we no > longer split new submissions. You must join split files together > before running BinHex or StuffIt. Hqx files can be edited as normal > text; therefore, you can use any word processor or append command on > your host to stitch the pieces together. There are some utilities > (unity and united) in disk/ to do this step for you. > > Many of our files also have been compressed to save space. You'll know > that they have been when the file name after converting to Macintosh > format ends with a .sit, .cpt, .sea, or .pit extension. Here is a > table to help you with the reconstruction: > > Extension Created By Recommended unpacker Notes > > .pit PackIt II StuffIt obsolete format > .sit StuffIt Compact Pro/StuffIt has type SIT! > StuffIt Deluxe Stuffit Expander has type SITD > .cpt Compact Pro Compact Pro > .sea various itself (double-click on it to unpack) > > > In summary, there are generally five steps to pulling .hqx files from our > archives: > 1. Transfer them to your computer with FTP. > 2. Transfer them to your Macintosh somehow. > 3. If necessary, put separate pieces together. > 4. Run a de-binhexing utility to convert the .hqx files into either > real Macintosh files or compressed Macintosh files. > 5. If they are compressed, use the appropriate decompression > program to decompress them. > People using Unix may be able to skip steps 3 and 4 by using the program > mcvert on their Unix system before transferring the program > to their Macintosh. > > If you don't already have BinHex 4.0, it would be easiest to get it > from a friend or user group. Or, if you know how to do an 8-bit binary > download, you can FTP it from us as cmp/binhex4.bin. Unfortunately, a > little bit of pulling yourself up by the bootstraps is required. > StuffIt Expander is a more modern and useful program which incoporates > the functionality of Binhex, while also decompressing files. It is > also available in cmp/ in both binary and binhexed forms. > > A CD-ROM of the archives is commercially available from Pacific HiTech. > They can be contacted by phone at 800-765-8369, > fax at 801-278-2666, and email > at 71175.3152@compuserve.com. The CD-ROM is approximately $45 including > shipping and handling. > > Please note that we cannot test software for reliability on all Macintosh > configurations. As the software in this archive is generally non-commercial, > it may be less reliable and more prone to crashes than you are used to. > > We highly recommend that you maintain an active backup procedure to protect > yourself even in the event of a system crash that results in the loss of > some of your data. Download and use all software in this archive at your own > risk. > > The Info-Mac Moderators > info-mac-request@sumex-aim.stanford.edu > >------ End Included Message ------ SHAR_EOF chmod 0444 README-conversion || echo 'restore of README-conversion failed' Wc_c="`wc -c < 'README-conversion'`" test 7655 -eq "$Wc_c" || echo 'README-conversion: original size 7655, current size' "$Wc_c" fi # ============= mcvert.idraw ============== if test -f 'mcvert.idraw' -a X"$1" != X"-c"; then echo 'x - skipping mcvert.idraw (File already exists)' else echo 'x - extracting mcvert.idraw (Text)' sed 's/^X//' << 'SHAR_EOF' > 'mcvert.idraw' && %!PS-Adobe-2.0 EPSF-1.2 %%DocumentFonts: Helvetica-Bold %%Pages: 1 %%BoundingBox: 69 66 547 688 %%EndComments X %% Contributed by %% Brian Bartholomew - bb@math.ufl.edu - Univ. of Florida Dept. of Mathematics %% Sat, 20 Feb 93 04:45:04 EST X 50 dict begin X /arrowHeight 8 def /arrowWidth 4 def /none null def /numGraphicParameters 17 def /stringLimit 65535 def X /Begin { save numGraphicParameters dict begin } def X /End { end restore } def X /SetB { dup type /nulltype eq { pop false /brushRightArrow idef false /brushLeftArrow idef true /brushNone idef } { /brushDashOffset idef /brushDashArray idef 0 ne /brushRightArrow idef 0 ne /brushLeftArrow idef /brushWidth idef false /brushNone idef } ifelse } def X /SetCFg { /fgblue idef /fggreen idef /fgred idef } def X /SetCBg { /bgblue idef /bggreen idef /bgred idef } def X /SetF { /printSize idef /printFont idef } def X /SetP { dup type /nulltype eq { pop true /patternNone idef } { dup -1 eq { /patternGrayLevel idef /patternString idef } { /patternGrayLevel idef } ifelse false /patternNone idef } ifelse } def X /BSpl { 0 begin storexyn newpath n 1 gt { 0 0 0 0 0 0 1 1 true subspline n 2 gt { 0 0 0 0 1 1 2 2 false subspline 1 1 n 3 sub { /i exch def i 1 sub dup i dup i 1 add dup i 2 add dup false subspline } for n 3 sub dup n 2 sub dup n 1 sub dup 2 copy false subspline } if n 2 sub dup n 1 sub dup 2 copy 2 copy false subspline patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if brushNone not { istroke } if 0 0 1 1 leftarrow n 2 sub dup n 1 sub dup rightarrow } if end } dup 0 4 dict put def X /Circ { newpath 0 360 arc patternNone not { ifill } if brushNone not { istroke } if } def X /CBSpl { 0 begin dup 2 gt { storexyn newpath n 1 sub dup 0 0 1 1 2 2 true subspline 1 1 n 3 sub { /i exch def i 1 sub dup i dup i 1 add dup i 2 add dup false subspline } for n 3 sub dup n 2 sub dup n 1 sub dup 0 0 false subspline n 2 sub dup n 1 sub dup 0 0 1 1 false subspline patternNone not { ifill } if brushNone not { istroke } if } { Poly } ifelse end } dup 0 4 dict put def X /Elli { 0 begin newpath 4 2 roll translate scale 0 0 1 0 360 arc patternNone not { ifill } if brushNone not { istroke } if end } dup 0 1 dict put def X /Line { 0 begin 2 storexyn newpath x 0 get y 0 get moveto x 1 get y 1 get lineto brushNone not { istroke } if 0 0 1 1 leftarrow 0 0 1 1 rightarrow end } dup 0 4 dict put def X /MLine { 0 begin storexyn newpath n 1 gt { x 0 get y 0 get moveto 1 1 n 1 sub { /i exch def x i get y i get lineto } for patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if brushNone not { istroke } if 0 0 1 1 leftarrow n 2 sub dup n 1 sub dup rightarrow } if end } dup 0 4 dict put def X /Poly { 3 1 roll newpath moveto -1 add { lineto } repeat closepath patternNone not { ifill } if brushNone not { istroke } if } def X /Rect { 0 begin /t exch def /r exch def /b exch def /l exch def newpath l b moveto l t lineto r t lineto r b lineto closepath patternNone not { ifill } if brushNone not { istroke } if end } dup 0 4 dict put def X /Text { ishow } def X /idef { dup where { pop pop pop } { exch def } ifelse } def X /ifill { 0 begin gsave patternGrayLevel -1 ne { fgred bgred fgred sub patternGrayLevel mul add fggreen bggreen fggreen sub patternGrayLevel mul add fgblue bgblue fgblue sub patternGrayLevel mul add setrgbcolor eofill } { eoclip originalCTM setmatrix pathbbox /t exch def /r exch def /b exch def /l exch def /w r l sub ceiling cvi def /h t b sub ceiling cvi def /imageByteWidth w 8 div ceiling cvi def /imageHeight h def bgred bggreen bgblue setrgbcolor eofill fgred fggreen fgblue setrgbcolor w 0 gt h 0 gt and { l b translate w h scale w h true [w 0 0 h neg 0 h] { patternproc } imagemask } if } ifelse grestore end } dup 0 8 dict put def X /istroke { gsave brushDashOffset -1 eq { [] 0 setdash 1 setgray } { brushDashArray brushDashOffset setdash fgred fggreen fgblue setrgbcolor } ifelse brushWidth setlinewidth originalCTM setmatrix stroke grestore } def X /ishow { 0 begin gsave fgred fggreen fgblue setrgbcolor /fontDict printFont findfont printSize scalefont dup setfont def /descender fontDict begin 0 [FontBBox] 1 get FontMatrix end transform exch pop def /vertoffset 0 descender sub printSize sub printFont /Courier ne printFont /Courier-Bold ne and { 1 add } if def { 0 vertoffset moveto show /vertoffset vertoffset printSize sub def } forall grestore end } dup 0 3 dict put def X /patternproc { 0 begin /patternByteLength patternString length def /patternHeight patternByteLength 8 mul sqrt cvi def /patternWidth patternHeight def /patternByteWidth patternWidth 8 idiv def /imageByteMaxLength imageByteWidth imageHeight mul stringLimit patternByteWidth sub min def /imageMaxHeight imageByteMaxLength imageByteWidth idiv patternHeight idiv patternHeight mul patternHeight max def /imageHeight imageHeight imageMaxHeight sub store /imageString imageByteWidth imageMaxHeight mul patternByteWidth add string def 0 1 imageMaxHeight 1 sub { /y exch def /patternRow y patternByteWidth mul patternByteLength mod def /patternRowString patternString patternRow patternByteWidth getinterval def /imageRow y imageByteWidth mul def 0 patternByteWidth imageByteWidth 1 sub { /x exch def imageString imageRow x add patternRowString putinterval } for } for imageString end } dup 0 12 dict put def X /min { dup 3 2 roll dup 4 3 roll lt { exch } if pop } def X /max { dup 3 2 roll dup 4 3 roll gt { exch } if pop } def X /arrowhead { 0 begin transform originalCTM itransform /taily exch def /tailx exch def transform originalCTM itransform /tipy exch def /tipx exch def /dy tipy taily sub def /dx tipx tailx sub def /angle dx 0 ne dy 0 ne or { dy dx atan } { 90 } ifelse def gsave originalCTM setmatrix tipx tipy translate angle rotate newpath 0 0 moveto arrowHeight neg arrowWidth 2 div lineto arrowHeight neg arrowWidth 2 div neg lineto closepath patternNone not { originalCTM setmatrix /padtip arrowHeight 2 exp 0.25 arrowWidth 2 exp mul add sqrt brushWidth mul arrowWidth div def /padtail brushWidth 2 div def tipx tipy translate angle rotate padtip 0 translate arrowHeight padtip add padtail add arrowHeight div dup scale arrowheadpath ifill } if brushNone not { originalCTM setmatrix tipx tipy translate angle rotate arrowheadpath istroke } if grestore end } dup 0 9 dict put def X /arrowheadpath { newpath 0 0 moveto arrowHeight neg arrowWidth 2 div lineto arrowHeight neg arrowWidth 2 div neg lineto closepath } def X /leftarrow { 0 begin y exch get /taily exch def x exch get /tailx exch def y exch get /tipy exch def x exch get /tipx exch def brushLeftArrow { tipx tipy tailx taily arrowhead } if end } dup 0 4 dict put def X /rightarrow { 0 begin y exch get /tipy exch def x exch get /tipx exch def y exch get /taily exch def x exch get /tailx exch def brushRightArrow { tipx tipy tailx taily arrowhead } if end } dup 0 4 dict put def X /midpoint { 0 begin /y1 exch def /x1 exch def /y0 exch def /x0 exch def x0 x1 add 2 div y0 y1 add 2 div end } dup 0 4 dict put def X /thirdpoint { 0 begin /y1 exch def /x1 exch def /y0 exch def /x0 exch def x0 2 mul x1 add 3 div y0 2 mul y1 add 3 div end } dup 0 4 dict put def X /subspline { 0 begin /movetoNeeded exch def y exch get /y3 exch def x exch get /x3 exch def y exch get /y2 exch def x exch get /x2 exch def y exch get /y1 exch def x exch get /x1 exch def y exch get /y0 exch def x exch get /x0 exch def x1 y1 x2 y2 thirdpoint /p1y exch def /p1x exch def x2 y2 x1 y1 thirdpoint /p2y exch def /p2x exch def x1 y1 x0 y0 thirdpoint p1x p1y midpoint /p0y exch def /p0x exch def x2 y2 x3 y3 thirdpoint p2x p2y midpoint /p3y exch def /p3x exch def movetoNeeded { p0x p0y moveto } if p1x p1y p2x p2y p3x p3y curveto end } dup 0 17 dict put def X /storexyn { /n exch def /y n array def /x n array def n 1 sub -1 0 { /i exch def y i 3 2 roll put x i 3 2 roll put } for } def X %%EndProlog X %I Idraw 7 Grid 8 X %%Page: 1 1 X Begin %I b u %I cfg u %I cbg u %I f u %I p u %I t [ 0.8 0 0 0.8 0 0 ] concat /originalCTM matrix currentmatrix def X Begin %I Rect %I b 65535 2 0 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg none SetP %I p n %I t [ 1 0 0 1 -72 275 ] concat %I 361 198 556 269 Rect End X Begin %I Rect %I b 65535 2 0 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg none SetP %I p n %I t [ 1 0 0 1 -271 479 ] concat %I 361 198 556 269 Rect End X Begin %I Rect %I b 65535 2 0 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg none SetP %I p n %I t [ 1 0 0 1 97 486 ] concat %I 361 198 556 269 Rect End X Begin %I Rect %I b 65535 2 0 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg none SetP %I p n %I t [ 1 0 0 1 125 81 ] concat %I 361 198 556 269 Rect End X Begin %I Rect %I b 65535 2 0 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg none SetP %I p n %I t [ 1 0 0 1 -269 85 ] concat %I 361 198 556 269 Rect End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 348 513 ] concat %I [ (MacBinary) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 513 723 ] concat %I [ (BinHex 4.0) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 150 324 ] concat %I [ (Data Fork) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 534 322 ] concat %I [ (Resource Fork) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 173 717 ] concat %I [ (Text) ] Text End X Begin %I Line %I b 65535 1 1 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg %I p 0 SetP %I t [ 1 0 0 1 -89 166 ] concat %I 287 500 373 393 Line End X Begin %I Line %I b 65535 1 0 1 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg %I p 0 SetP %I t [ 1 0 0 1 -69 167 ] concat %I 355 286 310 199 Line End X Begin %I Line %I b 65535 1 0 1 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg %I p 0 SetP %I t [ 1 0 0 1 -69 167 ] concat %I 547 290 609 198 Line End X Begin %I Line %I b 65535 1 0 1 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg %I p 0 SetP %I t [ 1 0 0 1 -69 167 ] concat %I 542 395 584 504 Line End X Begin %I Line %I b 65535 1 1 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg %I p 0 SetP %I t [ 1 0 0 1 -44 162 ] concat %I 542 395 584 504 Line End X Begin %I Line %I b 65535 1 0 1 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg %I p 0 SetP %I t [ 1 0 0 1 -58 170 ] concat %I 287 500 373 393 Line End X Begin %I Line %I b 65535 1 1 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg %I p 0 SetP %I t [ 1 0 0 1 -40 167 ] concat %I 355 286 310 199 Line End X Begin %I Line %I b 65535 1 1 0 [] 0 SetB %I cfg Black 0 0 0 SetCFg %I cbg White 1 1 1 SetCBg %I p 0 SetP %I t [ 1 0 0 1 -43 176 ] concat %I 547 290 609 198 Line End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 224 419 ] concat %I [ (-dU) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 304 406 ] concat %I [ (-dD) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 467 405 ] concat %I [ (-rU) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 553 429 ] concat %I [ (-rD) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 458 629 ] concat %I [ (-xU) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 536 613 ] concat %I [ (-xD) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 284 631 ] concat %I [ (-uD) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 199 611 ] concat %I [ (-uU) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 451 536 ] concat %I [ (.bin) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 619 748 ] concat %I [ (.hqx) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 274 150 ] concat %I [ (-s Silent) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 274 125 ] concat %I [ (-v Verbose) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 2.24324 0 0 2.24324 244 850.216 ] concat %I [ (mcvert\(1\) options) ] Text End X Begin %I Text %I cfg Black 0 0 0 SetCFg %I f *-helvetica-bold-r-*-140-* /Helvetica-Bold 14 SetF %I t [ 1 0 0 1 274 100 ] concat %I [ (-p Unpack top-level PackIt archives) ] Text End X End %I eop X showpage X %%Trailer X end SHAR_EOF chmod 0444 mcvert.idraw || echo 'restore of mcvert.idraw failed' Wc_c="`wc -c < 'mcvert.idraw'`" test 13179 -eq "$Wc_c" || echo 'mcvert.idraw: original size 13179, current size' "$Wc_c" fi # ============= mcvert.1 ============== if test -f 'mcvert.1' -a X"$1" != X"-c"; then echo 'x - skipping mcvert.1 (File already exists)' else echo 'x - extracting mcvert.1 (Text)' sed 's/^X//' << 'SHAR_EOF' > 'mcvert.1' && .TH MCVERT LOCAL "10Nov93" .UC 4.2 .SH NAME mcvert \- MacBinary <=> BinHex 4.0 and more file conversion utility .SH SYNOPSIS .B mcvert { [option] ... name ... } ... .br .SH DESCRIPTION The .I mcvert program translates files between MacBinary format and other formats often used in exchanging Macintosh files. See .I FILE FORMATS below for a description of the file formats supported. .SH PARAMETERS The defaults for the parameters are .RB - xDqv : convert BinHex 4.0 files .RB ( x ) to MacBinary files .RB ( D ), bypass automatic unpacking of PIT files .RB ( q ), and provide a verbose level of output .RB ( v ). .SH "OPTIONS" All the options, other than .I "FORMAT OPTIONS" described below, are listed here. XFrom each set, one and only one alternative is active for any one file. .TP .B U | D When option -U, as in Upload, is selected, the conversion is from MacBinary to something else. Conversely, option -D, as in Download, selects conversion from something to MacBinary. .TP .B p | q If a BinHex 4.0 to MacBinary conversion is taking place and option -p, as in Pit, is selected, any file of type "PIT " will be unpacked into its constituent parts. This option does not recursively unpack "PIT " files packed in "PIT " files. If a MacBinary to BinHex 4.0 conversion is taking place, this option is currently ignored. Conversely, option -q, as in Quiescent, does no such unpacking. .TP .B t Macintosh and UNIX differ in the end-of-line character they use. Option -t, as in Translate, enables end-of-line character translation for the data. Translation is off by default, but it is enabled automatically when processing -u (Usual Text) files. Option -t is useful when processing both data and resource files at the same time (option -b) to enable end-of-line character translation for the data. .TP .B S | s | v | V | VV Normally, .I mcvert prints converting messages and other information about the files it is processing to stderr. Option -S, as in SILENT, disables all such reporting. Option -s, as in Silent, disables all but the "Converting ..." messages. Option -v, as in Verbose, emits generally useful information. Option -V, as in VERBOSE, displays some additional debugging information. Option -VV, as in VERY VERBOSE, displays detailed debugging information as well. .TP .B H Option -H, as in Heuristic, disables the skip-legal-but-suspect-lines heuristic used when processing BinHex 4.0 formatted input files. See .I BUGS below for details on the heuristic. .TP .B I Option -I, as in Information only, does not write output files, but does indicate which output files would normally be written. All other operations are performed, including verifying file formats and calculated CRC values. The -I option basically provides a non-destructive verification of the files and their processing. It is also a soothing balm for the somewhat paranoid, since it reports what files would be changed, without actually changing them. .TP .B P Option -P, as in Pipe output to stdout, writes the resulting output file(s) to stdout, rather than to the file system with the appropriate extension. The default is to use the file system. .SH "FILE FORMATS" Some useful formats in which Macintosh files are represented on non-Macs are: .TP .B MacBinary: An eight bit wide representation of the data and resource forks of a Mac file and of relevant Finder information, MacBinary files are recognized as "special" by several Macintosh terminal emulators. These emulators, using kermit or xmodem or other file transfer protocols, can separate the incoming file into forks and appropriately modify the Desktop to display icons, types, creation dates, and the like. .TP .B BinHex 4.0: A seven bit wide representation of a Mac file with CRC error checking, BinHex 4.0 files are designed for communication of Mac files over long distance, possibly noisy, seven bit wide paths. .TP .B PackIt: PackIt files are actually representations of collections of Mac files, possibly Huffman compressed. Packing many small related files together before a MacBinary transfer or a translation to BinHex 4.0 is common practice. .TP .B Text: A Macintosh ends each line of a plain text file with a carriage return character (^M), rather than the newline character (^J) that some systems require (for example, UNIX). Moreover, a MacBinary file has prepended Finder information that non-Macintoshes usually don't expect. .TP .B Data, Rsrc: A Data or Rsrc file is the exact copy of the data or resource fork of a Macintosh file. .SH "FORMAT OPTIONS" Exactly one of the following selections may be specified for an input name: .TP .B x BinHex 4.0 [.hqx] - files in the MacBinary format are translated to BinHex 4.0 files, or vice versa. The name argument is the name of a file to be converted. If the conversion is from BinHex 4.0 to MacBinary, several files may comprise the BinHex 4.0 representation of the Mac file. Rather than manually concatenate the files and manually delete mail headers and other extraneous garbage, one may specify the names of the files in order and .I mcvert will do the concatenating and deleting. Conversely, in converting a MacBinary file to BinHex 4.0 format for mailing over long distances, one may be restricted to mail messages of no greater that some fixed length. In this case, .I mcvert can automatically divide the BinHex 4.0 file into pieces and label each piece appropriately. For details on automatically segmenting files, see the description of the .B MAC_LINE_LIMIT environment variable below. .TP .B u | h Text [.text] - files in the MacBinary format with nonempty data forks and empty resource forks are made from ordinary data files, or vice versa. Option -u, for Usual Text, performs translation. Option -h, for Host Text, performs no translation. When translating, UNIX newline characters are interchanged with Macintosh carriage return characters. .TP .B d Data [.data] - files in the MacBinary format with nonempty data forks and empty resource forks are made from ordinary data files, or vice versa. If the data is really text, you should use -u or -h so that the file type and creator get set correctly. .TP .B r Resource [.rsrc] - files in the MacBinary format with empty data forks and nonempty resource forks are made from ordinary data files, or vice versa. .TP .B b Both [.data .rsrc] - files in the MacBinary format with nonempty data forks and and nonempty resource forks are made from ordinary data files, or vice versa. For option -b processing, a single base file name is provided, and the ".data" and ".rsrc" extensions are supplied by .IR mcvert . .SH "FILE NAMES AND EXTENSIONS" .PP .I mcvert uses certain file extensions when reading and writing files. These extensions are indicated in the "FORMAT OPTIONS" section above. For example, the appropriate extension for a BinHex 4.0 file is ".hqx". .PP For input files, .I mcvert first tries to open the file using the specified name. If that fails, .I mcvert appends the appropriate suffix (if not already present) and tries again. Recall that for option -b (Both) processing, a single base file name must be provided, since the ".data" and ".rsrc" extensions are appended automatically by .IR mcvert . For example, "mcvert foo" will try to open "foo", and failing that, try to open "foo.hqx" for input; while "mcvert -b foo" will open only "foo.data" and "foo.rsrc" for input. .PP For output files, .I mcvert always uses the specified base file name and appropriate extension. For MacBinary and BinHex 4.0 input files, the base file name is specified within the input file, while for plain files, the file name specified on the command line is used. The appropriate extension is based on the conversion, or on the MAC_EXT environment variable for MacBinary output files. For example, if there is text file named foo.text (but no file named foo), "mcvert -u foo" will use foo.text as input, and generate a file called "foo.bin", while "mcvert -u foo.text" will use foo.text as input, and generate a file called "foo.text.bin". .SH "ENVIRONMENT VARIABLES AND DEFAULTS" There are five environment variables one may use to customize the behavior of .I mcvert slightly. .TP .B MAC_FILETYPE The file type of a MacBinary file converted from non BinHex 4.0 inputs is set to this four-character sequence. For example, one might set this variable to "PICT" when converting files created by ppmtopict(1). The default is "TEXT" for Text or Host inputs, and "????" otherwise. BinHex 4.0 inputs specify the file type to use internally. .TP .B MAC_EDITOR The creator type (author) of MacBinary files is set to this four-character sequence. The default is "MACA" (the creator type of MacWrite) for Text inputs, and "????" otherwise. BinHex 4.0 inputs specify the creator type to use internally. .TP .B MAC_DLOAD_DIR The MacBinary files created when option -D is selected are placed in this directory. The default is ".", the current working directory. .TP .B MAC_EXT The MacBinary files created when option -D is selected are named according to the file name field stored in the file header, with the name extended by this suffix. The default is ".bin". .TP .B MAC_LINE_LIMIT The BinHex 4.0 files created when option -U is selected may be no longer than this many lines long. Files that would otherwise exceed this line limit are broken up into several files with numbers embedded into their file names to show their order. Each such file has "Start of part x" and "End of part x" messages included where appropriate. .SH BUGS .PP .I mcvert silently discards input lines which are not completely valid. Therefore, error indications for illegally formatted files are likely to be somewhat obtuse, often with just a CRC mismatch message. .PP In order to handle files (such as segmented comp.binaries.mac files) which have extraneous but valid BinHex 4.0 lines (such as "---"), .I mcvert uses the following heuristic to discard suspect but legal lines in BinHex 4.0 formatted input files. When a new file is opened, or when invalid lines are found, the search for good data begins. While searching for good data, if a line is too short (less than 12 characters), or if a line is just a single repeated character, the line is discarded. Once .I mcvert starts processing good data, no valid lines are discarded. Thus, this heuristic can also discard (unusually formatted) valid and intended BinHex 4.0 lines. While there is no way to tune the heuristic (other than modifying the program and recompiling), the heuristic can be completely disabled with the .B -H option. So if you run into problems, put all the relevant lines into one file, edit the file to remove any extraneous lines, and invoke .I mcvert with the .B -H option. .PP It should be possible to discard bad input now and successfully translate good input later, but bad input usually causes immediate termination. .PP A more diligent person would support BinHex 3.0 and BinHex 2.0 and BinHex 5000 B. C., but I've never seen or heard of anyone using them in years. .SH "OTHER PROGRAMS" There are a number of programs which run on the Mac and convert between various Macintosh file formats. For example, here's what info-mac/help/accessing-files.txt, as of 13Jun93, has to say about converting between BinHex 4.0 and native Mac files: .RS X You can also do the conversion on your Macintosh by using any of a number of utilities, including BinHex 4.0, StuffIt, or Compact Pro. We recommend using Compact Pro because it is slightly more convenient and reliable than the other tools. Note: do NOT use BinHex 5.0 as it is incompatible, for some very brain-damaged reasons. .RE X CompactPro is a wonderful piece of shareware. But if your needs are limited to expansion of BinHex 4.0 files, StuffIt or CompactPro archives or AppleLink packages, then the freeware StuffIt Expander (v 3.0.3 as of 28Jul93) may be just what you want. .PP There are other programs available which run under UNIX and convert between various Macintosh file formats. One of these programs may be what you want to use if .I mcvert does not meet your needs. One collection, called .IR macutil , is available from various archives. Here's what the comp.sys.mac.comm FAQ (Frequently Asked Questions), Last-modified: Sat Jun 05 1993, has to say about it: .RS .IP "As of (8/92), macutil includes three programs:" .IP hexbin a program to convert BinHex 4.0 to MacBinary; it also converts uuencode (and UULite) files to their native binary format; support for .dl, .hex, and .hcx formats (all predecessors of BinHex 4.0) also exists .IP macsave a MacBinary filter program to convert between various MacBinary representations, including a single .bin file, three separate .data, .rsrc, .info files, and AUFS format. macsave also allows one to "peek" inside MacBinary files .IP macunpack a program to unpack PackIt, StuffIt, Diamond, Compactor/Compact Pro, most StuffIt Classic and StuffIt Deluxe, DiskDoubler, Zoom and LHarc/MacLHa archives. X It also decodes BinHex 5.0, MacBinary, uuencode, and UNIX compress (ie: .Z suffix) files (as well as variants of compress implemented by various Macintosh compress programs). X Support for password protected and/or multi-segment archives of various types is minimal or non-existent. .RE .SH "SEE ALSO" hexbin(1), kermit(1), macbin(1), macunpack(1), macsave(1), macutil(1), ppmtopict(1), sit(1), unsit(1), xbin(1), xmodem(1) .SH AUTHORS Doug Moore, Cornell University Computer Science. Based upon .I xbin by Dave Johnson, Brown University, as modified by Guido van Rossum, and upon .I unpit by Allan G. Weber, as well as upon correspondence with several helpful readers of USENET. .PP Joseph P. Skudlarek (Jskud@wv.MentorG.com) made numerous enhancement and maintenance releases. See the comments in mcvert.c for additional supporting characters. SHAR_EOF chmod 0444 mcvert.1 || echo 'restore of mcvert.1 failed' Wc_c="`wc -c < 'mcvert.1'`" test 13789 -eq "$Wc_c" || echo 'mcvert.1: original size 13789, current size' "$Wc_c" fi # ============= mcvert.man ============== if test -f 'mcvert.man' -a X"$1" != X"-c"; then echo 'x - skipping mcvert.man (File already exists)' else echo 'x - extracting mcvert.man (Text)' sed 's/^X//' << 'SHAR_EOF' > 'mcvert.man' && X X X X MCVERT(LOCAL) MCVERT(LOCAL) X 10Nov93 X X X X NAME X mcvert - MacBinary <=> BinHex 4.0 and more file conversion utility X X SYNOPSIS X mcvert { [option] ... name ... } ... X X DESCRIPTION X The mcvert program translates files between MacBinary format and other X formats often used in exchanging Macintosh files. See FILE FORMATS X below for a description of the file formats supported. X X PARAMETERS X The defaults for the parameters are -xDqv: convert BinHex 4.0 files X (x) to MacBinary files (D), bypass automatic unpacking of PIT files X (q), and provide a verbose level of output (v). X X OPTIONS X All the options, other than FORMAT OPTIONS described below, are listed X here. From each set, one and only one alternative is active for any X one file. X X U | D X When option -U, as in Upload, is selected, the conversion is from X MacBinary to something else. Conversely, option -D, as in X Download, selects conversion from something to MacBinary. X X p | q X If a BinHex 4.0 to MacBinary conversion is taking place and X option -p, as in Pit, is selected, any file of type "PIT " will X be unpacked into its constituent parts. This option does not X recursively unpack "PIT " files packed in "PIT " files. If a X MacBinary to BinHex 4.0 conversion is taking place, this option X is currently ignored. Conversely, option -q, as in Quiescent, X does no such unpacking. X X t Macintosh and UNIX differ in the end-of-line character they use. X Option -t, as in Translate, enables end-of-line character X translation for the data. Translation is off by default, but it X is enabled automatically when processing -u (Usual Text) files. X Option -t is useful when processing both data and resource files X at the same time (option -b) to enable end-of-line character X translation for the data. X X S | s | v | V | VV X Normally, mcvert prints converting messages and other information X about the files it is processing to stderr. Option -S, as in X SILENT, disables all such reporting. Option -s, as in Silent, X disables all but the "Converting ..." messages. Option -v, as in X Verbose, emits generally useful information. Option -V, as in X VERBOSE, displays some additional debugging information. Option X -VV, as in VERY VERBOSE, displays detailed debugging information X X X X - 1 - Formatted: October 14, 1994 X X X X X X X MCVERT(LOCAL) MCVERT(LOCAL) X 10Nov93 X X X X as well. X X H Option -H, as in Heuristic, disables the skip-legal-but-suspect- X lines heuristic used when processing BinHex 4.0 formatted input X files. See BUGS below for details on the heuristic. X X I Option -I, as in Information only, does not write output files, X but does indicate which output files would normally be written. X All other operations are performed, including verifying file X formats and calculated CRC values. The -I option basically X provides a non-destructive verification of the files and their X processing. It is also a soothing balm for the somewhat X paranoid, since it reports what files would be changed, without X actually changing them. X X P Option -P, as in Pipe output to stdout, writes the resulting X output file(s) to stdout, rather than to the file system with the X appropriate extension. The default is to use the file system. X X FILE FORMATS X Some useful formats in which Macintosh files are represented on non- X Macs are: X X MacBinary: X An eight bit wide representation of the data and resource forks X of a Mac file and of relevant Finder information, MacBinary files X are recognized as "special" by several Macintosh terminal X emulators. These emulators, using kermit or xmodem or other file X transfer protocols, can separate the incoming file into forks and X appropriately modify the Desktop to display icons, types, X creation dates, and the like. X X BinHex 4.0: X A seven bit wide representation of a Mac file with CRC error X checking, BinHex 4.0 files are designed for communication of Mac X files over long distance, possibly noisy, seven bit wide paths. X X PackIt: X PackIt files are actually representations of collections of Mac X files, possibly Huffman compressed. Packing many small related X files together before a MacBinary transfer or a translation to X BinHex 4.0 is common practice. X X Text: X A Macintosh ends each line of a plain text file with a carriage X return character (^M), rather than the newline character (^J) X that some systems require (for example, UNIX). Moreover, a X MacBinary file has prepended Finder information that non- X Macintoshes usually don't expect. X X X X X X - 2 - Formatted: October 14, 1994 X X X X X X X MCVERT(LOCAL) MCVERT(LOCAL) X 10Nov93 X X X X Data, Rsrc: X A Data or Rsrc file is the exact copy of the data or resource X fork of a Macintosh file. X X FORMAT OPTIONS X Exactly one of the following selections may be specified for an input X name: X X x BinHex 4.0 [.hqx] - files in the MacBinary format are translated X to BinHex 4.0 files, or vice versa. The name argument is the X name of a file to be converted. If the conversion is from BinHex X 4.0 to MacBinary, several files may comprise the BinHex 4.0 X representation of the Mac file. Rather than manually concatenate X the files and manually delete mail headers and other extraneous X garbage, one may specify the names of the files in order and X mcvert will do the concatenating and deleting. Conversely, in X converting a MacBinary file to BinHex 4.0 format for mailing over X long distances, one may be restricted to mail messages of no X greater that some fixed length. In this case, mcvert can X automatically divide the BinHex 4.0 file into pieces and label X each piece appropriately. For details on automatically X segmenting files, see the description of the MAC_LINE_LIMIT X environment variable below. X X u | h X Text [.text] - files in the MacBinary format with nonempty data X forks and empty resource forks are made from ordinary data files, X or vice versa. Option -u, for Usual Text, performs translation. X Option -h, for Host Text, performs no translation. When X translating, UNIX newline characters are interchanged with X Macintosh carriage return characters. X X d Data [.data] - files in the MacBinary format with nonempty data X forks and empty resource forks are made from ordinary data files, X or vice versa. If the data is really text, you should use -u or X -h so that the file type and creator get set correctly. X X r Resource [.rsrc] - files in the MacBinary format with empty data X forks and nonempty resource forks are made from ordinary data X files, or vice versa. X X b Both [.data .rsrc] - files in the MacBinary format with nonempty X data forks and and nonempty resource forks are made from ordinary X data files, or vice versa. For option -b processing, a single X base file name is provided, and the ".data" and ".rsrc" X extensions are supplied by mcvert. X X FILE NAMES AND EXTENSIONS X mcvert uses certain file extensions when reading and writing files. X These extensions are indicated in the "FORMAT OPTIONS" section above. X For example, the appropriate extension for a BinHex 4.0 file is X X X X - 3 - Formatted: October 14, 1994 X X X X X X X MCVERT(LOCAL) MCVERT(LOCAL) X 10Nov93 X X X X ".hqx". X X For input files, mcvert first tries to open the file using the X specified name. If that fails, mcvert appends the appropriate suffix X (if not already present) and tries again. Recall that for option -b X (Both) processing, a single base file name must be provided, since the X ".data" and ".rsrc" extensions are appended automatically by mcvert. X For example, "mcvert foo" will try to open "foo", and failing that, X try to open "foo.hqx" for input; while "mcvert -b foo" will open only X "foo.data" and "foo.rsrc" for input. X X For output files, mcvert always uses the specified base file name and X appropriate extension. For MacBinary and BinHex 4.0 input files, the X base file name is specified within the input file, while for plain X files, the file name specified on the command line is used. The X appropriate extension is based on the conversion, or on the MAC_EXT X environment variable for MacBinary output files. For example, if X there is text file named foo.text (but no file named foo), "mcvert -u X foo" will use foo.text as input, and generate a file called "foo.bin", X while "mcvert -u foo.text" will use foo.text as input, and generate a X file called "foo.text.bin". X X ENVIRONMENT VARIABLES AND DEFAULTS X There are five environment variables one may use to customize the X behavior of mcvert slightly. X X MAC_FILETYPE X The file type of a MacBinary file converted from non BinHex 4.0 X inputs is set to this four-character sequence. For example, one X might set this variable to "PICT" when converting files created X by ppmtopict(1). The default is "TEXT" for Text or Host inputs, X and "????" otherwise. BinHex 4.0 inputs specify the file type to X use internally. X X MAC_EDITOR X The creator type (author) of MacBinary files is set to this X four-character sequence. The default is "MACA" (the creator type X of MacWrite) for Text inputs, and "????" otherwise. BinHex 4.0 X inputs specify the creator type to use internally. X X MAC_DLOAD_DIR X The MacBinary files created when option -D is selected are placed X in this directory. The default is ".", the current working X directory. X X MAC_EXT X The MacBinary files created when option -D is selected are named X according to the file name field stored in the file header, with X the name extended by this suffix. The default is ".bin". X X X X X X - 4 - Formatted: October 14, 1994 X X X X X X X MCVERT(LOCAL) MCVERT(LOCAL) X 10Nov93 X X X X MAC_LINE_LIMIT X The BinHex 4.0 files created when option -U is selected may be no X longer than this many lines long. Files that would otherwise X exceed this line limit are broken up into several files with X numbers embedded into their file names to show their order. Each X such file has "Start of part x" and "End of part x" messages X included where appropriate. X X BUGS X mcvert silently discards input lines which are not completely valid. X Therefore, error indications for illegally formatted files are likely X to be somewhat obtuse, often with just a CRC mismatch message. X X In order to handle files (such as segmented comp.binaries.mac files) X which have extraneous but valid BinHex 4.0 lines (such as "---"), X mcvert uses the following heuristic to discard suspect but legal lines X in BinHex 4.0 formatted input files. When a new file is opened, or X when invalid lines are found, the search for good data begins. While X searching for good data, if a line is too short (less than 12 X characters), or if a line is just a single repeated character, the X line is discarded. Once mcvert starts processing good data, no valid X lines are discarded. Thus, this heuristic can also discard (unusually X formatted) valid and intended BinHex 4.0 lines. While there is no way X to tune the heuristic (other than modifying the program and X recompiling), the heuristic can be completely disabled with the -H X option. So if you run into problems, put all the relevant lines into X one file, edit the file to remove any extraneous lines, and invoke X mcvert with the -H option. X X It should be possible to discard bad input now and successfully X translate good input later, but bad input usually causes immediate X termination. X X A more diligent person would support BinHex 3.0 and BinHex 2.0 and X BinHex 5000 B. C., but I've never seen or heard of anyone using them X in years. X X OTHER PROGRAMS X There are a number of programs which run on the Mac and convert X between various Macintosh file formats. For example, here's what X info-mac/help/accessing-files.txt, as of 13Jun93, has to say about X converting between BinHex 4.0 and native Mac files: X X You can also do the conversion on your Macintosh by using any of X a number of utilities, including BinHex 4.0, StuffIt, or Compact X Pro. We recommend using Compact Pro because it is slightly more X convenient and reliable than the other tools. Note: do NOT use X BinHex 5.0 as it is incompatible, for some very brain-damaged X reasons. X X CompactPro is a wonderful piece of shareware. But if your needs are X X X X - 5 - Formatted: October 14, 1994 X X X X X X X MCVERT(LOCAL) MCVERT(LOCAL) X 10Nov93 X X X X limited to expansion of BinHex 4.0 files, StuffIt or CompactPro X archives or AppleLink packages, then the freeware StuffIt Expander (v X 3.0.3 as of 28Jul93) may be just what you want. X X There are other programs available which run under UNIX and convert X between various Macintosh file formats. One of these programs may be X what you want to use if mcvert does not meet your needs. One X collection, called macutil, is available from various archives. X Here's what the comp.sys.mac.comm FAQ (Frequently Asked Questions), X Last-modified: Sat Jun 05 1993, has to say about it: X X As of (8/92), macutil includes three programs: X X hexbin X a program to convert BinHex 4.0 to MacBinary; it also X converts uuencode (and UULite) files to their native binary X format; support for .dl, .hex, and .hcx formats (all X predecessors of BinHex 4.0) also exists X X macsave X a MacBinary filter program to convert between various X MacBinary representations, including a single .bin file, X three separate .data, .rsrc, .info files, and AUFS format. X macsave also allows one to "peek" inside MacBinary files X X macunpack X a program to unpack PackIt, StuffIt, Diamond, X Compactor/Compact Pro, most StuffIt Classic and StuffIt X Deluxe, DiskDoubler, Zoom and LHarc/MacLHa archives. X X It also decodes BinHex 5.0, MacBinary, uuencode, and UNIX X compress (ie: .Z suffix) files (as well as variants of X compress implemented by various Macintosh compress X programs). X X Support for password protected and/or multi-segment archives X of various types is minimal or non-existent. X X SEE ALSO X hexbin(1), kermit(1), macbin(1), macunpack(1), macsave(1), macutil(1), X ppmtopict(1), sit(1), unsit(1), xbin(1), xmodem(1) X X AUTHORS X Doug Moore, Cornell University Computer Science. Based upon xbin by X Dave Johnson, Brown University, as modified by Guido van Rossum, and X upon unpit by Allan G. Weber, as well as upon correspondence with X several helpful readers of USENET. X X Joseph P. Skudlarek (Jskud@wv.MentorG.com) made numerous enhancement X and maintenance releases. See the comments in mcvert.c for additional X supporting characters. X X X X - 6 - Formatted: October 14, 1994 X X X SHAR_EOF chmod 0644 mcvert.man || echo 'restore of mcvert.man failed' Wc_c="`wc -c < 'mcvert.man'`" test 16929 -eq "$Wc_c" || echo 'mcvert.man: original size 16929, current size' "$Wc_c" fi exit 0 <<Signature>> /Jskud ---------------------------------------------------------------------------- Joseph P. Skudlarek Mentor Graphics 8005 SW Boeckman Rd Wilsonville OR 97070 Jskud@wv.MentorG.com Joseph_Skudlarek@MentorG.com 503/685-1576@work