home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Atlanta_1990 / Atlanta-Devcon.2 / Libraries / IFFParse / Examples / looki.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-26  |  20.5 KB  |  879 lines

  1. /*  :ts=8 bk=0
  2.  *
  3.  * looki.c:    Yet Another ILBM Viewer, except this one uses the new
  4.  *        iffparse.library.
  5.  *
  6.  * Written for Lattice 5.05.  This program is constructed by saying:
  7.  * 1> lc -cq -v -L looki.c
  8.  *
  9.  * Note:  This program isn't as fully featured as I'd like (I started late).
  10.  * In particular, I'd have liked it to have color cycling capability (toggled
  11.  * on and off by hitting TAB), and the ability to turn the title bar on and
  12.  * off with F10.
  13.  *
  14.  * Another thing to note is that, because many pictures were/are written
  15.  * incorrectly, this program determines whether HIRES and/or LACE should be
  16.  * set based on the CAMG chunk, which is incorrect (this information should
  17.  * be derived from the XAspect/YAspect fields).  However, the program will
  18.  * note an inconsistency and flame about it.
  19.  *
  20.  * Even with this capability, there are still some images that it won't
  21.  * display "correctly".  In particular, I have encountered some 640 x 200
  22.  * images saved with no CAMG chunk and with an X/Y aspect ratio of 10/11.
  23.  * Thus, these images will be displayed in hi-res *interlace*, because that's
  24.  * what the BMHD specifies: nearly-square pixels.  I refuse to install a
  25.  * special case hack to compensate for this (because I'm a self-righteously
  26.  * indignant kinda guy.  So there :-) ).  I contend I am doing The Right
  27.  * Thing.  If the files were written wrong, then they should look wrong.
  28.  * 
  29.  * This code is provided AS IS.  No warranties, either expressed or implied,
  30.  * of any kind are made.  Damages or misfortune arising from the use or
  31.  * misuse of this code are the sole responsibility of the individual using
  32.  * or misusing it.
  33.  *
  34.  * Leo L. Schwab (original Manx 3.4b version)        8906.02
  35.  * Took floating point math out, fixed bugs.        8907.08
  36.  * Updated for 1.4 Beta.                8912.06
  37.  * Converted to Lattice 5.05.                9005.23
  38.  */
  39. #include <exec/types.h>
  40. #include <utility/hooks.h>
  41. #include <intuition/intuition.h>
  42. #include <libraries/iffparse.h>
  43. #include <clib/exec_protos.h>
  44. #include <clib/intuition_protos.h>
  45. #include <clib/graphics_protos.h>
  46. #include <stdio.h>
  47. #include "iffparse_protos.h"
  48. #include "iffparse.p"
  49. #include "myilbm.h"
  50.  
  51. #define    MAX(a,b)    ((a) > (b) ? (a) : (b))
  52. #define    MIN(a,b)    ((a) < (b) ? (a) : (b))
  53. #define    ABS(x)        ((x) < 0 ? -(x) : (x))
  54. #define    BPR(w)        ((w) + 15 >> 4 << 1)
  55.  
  56. /*  Note:  These are arbitrary numbers I pulled out of thin air.  */
  57. #define    MAXLORES    512
  58. #define    MAXNONLACE    320
  59. #define    IDEALRATIO    (10L * 1000 / 11)
  60.  
  61.  
  62. /*
  63.  * Forward function declarations.  (I hate ANSI.)
  64.  */
  65. LONG handlefile (struct IFFHandle *, char *);
  66. LONG displayfile (struct IFFHandle *, char *);
  67. LONG displayimage (struct IFFHandle *, char *);
  68. LONG loadbody (struct IFFHandle *);
  69. LONG createscreen (struct IFFHandle *, struct BitMapHeader *);
  70. LONG loadbitmap (struct IFFHandle *, struct BitMapHeader *, struct BitMap *);
  71. LONG loadline (struct IFFHandle *, UBYTE *, int, int, int);
  72. LONG printIFFerr (LONG);
  73. void deletescreen (void);
  74. void setcolors (struct IFFHandle *, struct BitMapHeader *);
  75. void initiffasstdio (struct IFFHandle *);
  76. void openstuff (void);
  77. void closestuff (void);
  78. void die (char *);
  79.  
  80.  
  81. struct Screen        *scr, sensor;
  82. struct Window        *win;
  83. struct IFFHandle    *iff;
  84.  
  85. struct IntuitionBase    *IntuitionBase;
  86. struct GfxBase        *GfxBase;
  87. struct Library        *IFFParseBase;
  88.  
  89.  
  90. main (ac, av)
  91. int    ac;
  92. char    **av;
  93. {
  94.     static char    usage[] =
  95. "Usage: %s file [file ... ]    ; For viewing files.\n\
  96.    or  %s -c            ; For viewing the clipboard.\n\
  97. Click mouse button anywhere when finished looking.\n";
  98.  
  99.     /*
  100.      * Check for arguments.  WorkBench startup not currently supported.
  101.      */
  102.     if (ac < 2)
  103.         if (ac == 1) {
  104.             printf (usage, *av, *av);
  105.             exit (20);
  106.         }
  107.  
  108.     openstuff ();
  109.  
  110.     ac--;
  111.     while (ac--)
  112.         handlefile (iff, *++av);
  113.  
  114.     closestuff ();
  115.  
  116.     return (0);
  117. }
  118.  
  119. LONG
  120. handlefile (iff, filename)
  121. struct IFFHandle    *iff;
  122. register char        *filename;
  123. {
  124.     LONG    error;
  125.     char    cboard;
  126.  
  127.     cboard = (*filename == '-'  &&  filename[1] == 'c');
  128.  
  129.     if (cboard) {
  130.         /*
  131.          * Set up IFFHandle for Clipboard I/O.
  132.          */
  133.         if (!(iff->iff_Stream =
  134.                 (ULONG) OpenClipboard (PRIMARY_CLIP)))
  135.         {
  136.             puts ("Clipboard open failed.");
  137.             return (FALSE);
  138.         }
  139.         InitIFFasClip (iff);
  140.     } else {
  141.         /*
  142.          * Set up IFFHandle for buffered stdio I/O.
  143.          */
  144.         if (!(iff->iff_Stream = (ULONG) fopen (filename, "r"))) {
  145.             printf ("%s: File open failed.\n", filename);
  146.             return (FALSE);
  147.         }
  148.         initiffasstdio (iff);
  149.     }
  150.  
  151.     printf ("%s: ", cboard ? "[Clipboard]" : filename);
  152.     fflush (stdout);
  153.     OpenIFF (iff, IFFF_READ);
  154.  
  155.     error = printIFFerr (displayfile (iff, filename));
  156.  
  157.     CloseIFF (iff);
  158.     deletescreen ();
  159.     fputs ("\r\233K", stdout);
  160.     if (cboard)
  161.         CloseClipboard ((struct ClipboardHandle *) iff->iff_Stream);
  162.     else
  163.         fclose ((FILE *) iff->iff_Stream);
  164.  
  165.     return (error);
  166. }
  167.  
  168. LONG
  169. displayfile (iff, filename)
  170. register struct IFFHandle *iff;
  171. char              *filename;
  172. {
  173.     /*
  174.      * Properties that will be collected automatically.
  175.      */
  176.     static LONG            ilbmprops[] = {
  177.         ID_ILBM, ID_BMHD,
  178.         ID_ILBM, ID_CMAP,
  179.         ID_ILBM, ID_CAMG
  180.     };
  181.     register struct ContextNode    *cn;
  182.     register LONG            error;
  183.     char                foundbody = 0, hunt = 0;
  184.  
  185.     /*
  186.      * Declare property, collection and stop chunks.
  187.      */
  188.     if (error = PropChunks (iff, ilbmprops, 3L))
  189.         return (error);
  190.     if (error = CollectionChunk (iff, ID_ILBM, ID_CRNG))
  191.         return (error);
  192.     if (error = StopChunk (iff, ID_ILBM, ID_BODY))
  193.         return (error);
  194.  
  195.     /*
  196.      * We want to stop at the end of an ILBM context.
  197.      */
  198.     if (error = StopOnExit (iff, ID_ILBM, ID_FORM))
  199.         return (error);
  200.  
  201.     /*
  202.      * Take first parse step to enter main chunk.
  203.      */
  204.     if (error = ParseIFF (iff, IFFPARSE_STEP))
  205.         return (error);
  206.  
  207.     /*
  208.      * Test the chunk info to see if this is a simple ILBM.
  209.      */
  210.     if (!(cn = CurrentChunk (iff))) {
  211.         /*
  212.          * This really should never happen.  If it does, it means
  213.          * our parser is broken.
  214.          */
  215.         puts ("Weird parsing error; no top chunk!");
  216.         return (1);
  217.     }
  218.     if (cn->cn_ID != ID_FORM  ||  cn->cn_Type != ID_ILBM) {
  219.         printf
  220.          ("This is a(n) %.4s.%.4s.  Looking for embedded ILBMs...",
  221.           &cn->cn_Type, &cn->cn_ID);
  222.         fflush (stdout);
  223.         hunt = TRUE;
  224.     }
  225.  
  226.     /*
  227.      * Start scanning the file looking for interesting things.
  228.      * The parser will do all the yucky IFF work for us.
  229.      */
  230.     while (!error) {
  231.         /*
  232.          * ParseIFF() will return on BODY chunk or end of
  233.          * context for an ILBM FORM.
  234.          */
  235.         error = ParseIFF (iff, IFFPARSE_SCAN);
  236.  
  237.         /*
  238.          * If we've left the ILBM FORM context, then we now have
  239.          * collected all possible information.  We are now ready
  240.          * to display the image.
  241.          */
  242.         if (error == IFFERR_EOC) {
  243.             error = displayimage (iff, filename);
  244.             deletescreen ();
  245.             if (error)
  246.                 break;
  247.             continue;
  248.         }
  249.  
  250.         /*
  251.          * Other values for error are real errors.
  252.          */
  253.         if (error)
  254.             break;
  255.  
  256.         /*
  257.          * NULL error means that we've stopped on an ILBM.BODY.
  258.          */
  259.         if (error = loadbody (iff))
  260.             return (error);
  261.         foundbody = TRUE;
  262.     }
  263.  
  264.     if (error == IFFERR_EOF)
  265.         if (!foundbody) {
  266.             if (hunt)
  267.                 puts ("None found.");
  268.             else
  269.                 puts ("No imagery to display.");
  270.             return (1);
  271.         } else {
  272.             if (hunt)
  273.                 putchar ('\n');
  274.             return (0);
  275.         }
  276.     else
  277.         return (error);
  278. }
  279.  
  280. LONG
  281. displayimage (iff, filename)
  282. struct IFFHandle    *iff;
  283. char            *filename;
  284. {
  285.     if (scr) {
  286.         /*  Well, we must have found *something*...  */
  287.         register struct View    *view;
  288.         register int        sw, sh, oldx, oldy;
  289.  
  290.         oldx = oldy = 0;
  291.  
  292.         sw = scr->Width;
  293.         if (scr->ViewPort.Modes & HIRES)
  294.             sw >>= 1;
  295.         sh = scr->Height;
  296.         if (scr->ViewPort.Modes & LACE)
  297.             sh >>= 1;
  298.  
  299.         if (sw > sensor.Width  &&  sh > sensor.Height) {
  300.             /*
  301.              * Overscan;  center view.
  302.              * Note:  Jim Mackraz says that it is more correct
  303.              * to shift the whole world to center an overscan
  304.              * screen.  Personally, I disagree, as I see no
  305.              * reason to shift all screens to center just one.
  306.              * But he's God, so what can I say?
  307.              */
  308.             view = ViewAddress ();
  309.  
  310.             oldx = view->DxOffset;
  311.             oldy = view->DyOffset;
  312.  
  313.             view->DxOffset += sensor.Width - sw >> 1;
  314.             view->DyOffset += sensor.Height - sh >> 1;
  315.             RemakeDisplay ();
  316.         }
  317.         SetWindowTitles (win, (char *) -1L, filename);
  318.         ScreenToFront (scr);
  319.         ActivateWindow (win);
  320.  
  321.         /*  Wait for a mouse click.  */
  322.         WaitPort (win->UserPort);
  323.  
  324.         if (oldx  ||  oldy) {
  325.             /*  Unshift the world.  */
  326.             view->DxOffset = oldx;
  327.             view->DyOffset = oldy;
  328.             RemakeDisplay ();
  329.         }
  330.     }
  331.     return (0);
  332. }
  333.  
  334. LONG
  335. loadbody (iff)
  336. struct IFFHandle *iff;
  337. {
  338.     register struct StoredProperty    *sp;
  339.     register struct BitMapHeader    *bmhd;
  340.     LONG                error;
  341.  
  342.     if (!(sp = FindProp (iff, ID_ILBM, ID_BMHD))) {
  343.         puts ("No ILBM.BMHD chunk!");
  344.         return (1);
  345.     }
  346.     bmhd = (struct BitMapHeader *) sp->sp_Data;
  347.  
  348.     if (error = createscreen (iff, bmhd))
  349.         return (error);
  350.  
  351.     setcolors (iff, bmhd);
  352.  
  353.     return (loadbitmap (iff, bmhd, &scr->BitMap));
  354. }
  355.  
  356. LONG
  357. createscreen (iff, bmhd)
  358. struct IFFHandle        *iff;
  359. register struct BitMapHeader    *bmhd;
  360. {
  361.     static struct NewScreen        scrdef = {
  362.         0, 0, 0, 0, 0,
  363.         0, 1,
  364.         NULL,            /*  Modes  */
  365.         CUSTOMSCREEN,        /* | SCREENBEHIND,    */
  366.         NULL,
  367.         NULL,
  368.         NULL, NULL,
  369.     };
  370.     static struct NewWindow        windef = {
  371.         0, 0, 0, 0,
  372.         -1, -1,
  373.         MOUSEBUTTONS,
  374.         BORDERLESS | BACKDROP,
  375.         NULL, NULL, NULL,
  376.         NULL,            /*  Screen filled in later.  */
  377.         NULL,
  378.         0, 0, 0, 0,
  379.         CUSTOMSCREEN
  380.     };
  381.     register struct StoredProperty    *sp;
  382.     long                ratio;
  383.     ULONG                camg;
  384.     UWORD                wide, high, modes;
  385.  
  386.     wide = MAX (bmhd->w, bmhd->PageWidth);
  387.     high = MAX (bmhd->h, bmhd->PageHeight);
  388.  
  389.     if (bmhd->YAspect)
  390.         ratio = bmhd->XAspect * 1000 / bmhd->YAspect;
  391.     else
  392.         ratio = 0;
  393.  
  394.     /*
  395.      * Compute what HIRES/LACE *should* be set to.  Allow 15% leeway.
  396.      * (See note in opening comment.)
  397.      * Note:  This does not yet handle superhires.
  398.      */
  399.     if (ABS (ratio - IDEALRATIO) < 150)
  400.         /*  Nearly square pixels.  */
  401.         if (wide >= MAXLORES)
  402.             modes = HIRES | LACE;
  403.         else
  404.             modes = 0;
  405.     else if (ABS (ratio - IDEALRATIO * 2) < 150)
  406.         /*  Short, wide pixels.  */
  407.         modes = LACE;
  408.     else if (ABS (ratio - IDEALRATIO / 2) < 150)
  409.         /*  Tall, narrow pixels.  */
  410.         modes = HIRES;
  411.     else {
  412.         /*  Weird aspect ratio; we'll have to guess...  */
  413.         modes = 0;
  414.         if (wide >= MAXLORES)
  415.             modes |= HIRES;
  416.         if (high >= MAXNONLACE)
  417.             modes |= LACE;
  418.     }
  419.  
  420.     /*
  421.      * Grab CAMG's idea of the viewmodes.
  422.      */
  423.     if (sp = FindProp (iff, ID_ILBM, ID_CAMG)) {
  424.         camg = * (ULONG *) sp->sp_Data;
  425.         scrdef.ViewModes =
  426.          (camg & (HIRES | LACE | DUALPF | HAM | EXTRA_HALFBRITE));
  427.         if (modes ^ (camg & (HIRES | LACE)))
  428. /*- - - - - - - - - - -*/
  429. printf ("XAspect/YAspect (%d/%d) inconsistent with CAMG.\n",
  430.     bmhd->XAspect, bmhd->YAspect);
  431. /*- - - - - - - - - - -*/
  432.     } else {
  433.         /*
  434.          * No CAMG present; use computed modes.
  435.          */
  436.         scrdef.ViewModes = modes;
  437.         if (bmhd->nplanes == 6)
  438.             /*
  439.              * With 6 planes and the absence of a CAMG, we have
  440.              * to make an assumption.  I assume HAM.
  441.              */
  442.             scrdef.ViewModes |= HAM;
  443.     }
  444.  
  445.     /*
  446.      * Open the screen and window.
  447.      */
  448.     deletescreen ();
  449.     scrdef.Width    = wide;
  450.     scrdef.Height    = high;
  451.     scrdef.Depth    = bmhd->nplanes;
  452.     if (!(scr = OpenScreen (&scrdef))) {
  453.         puts ("Failed to open display screen.");
  454.         return (1);
  455.     }
  456.  
  457.     windef.Screen    = scr;
  458.     windef.Width    = wide;
  459.     windef.Height    = high;
  460.     if (!(win = OpenWindow (&windef))) {
  461.         puts ("Failed to open window.");
  462.         return (1);
  463.     }
  464.     ShowTitle (scr, FALSE);
  465.     return (0);
  466. }
  467.  
  468. void
  469. deletescreen ()
  470. {
  471.     if (win)    CloseWindow (win), win = NULL;
  472.     if (scr)    CloseScreen (scr), scr = NULL;
  473. }
  474.  
  475. void
  476. setcolors (iff, bmhd)
  477. struct IFFHandle        *iff;
  478. register struct BitMapHeader    *bmhd;
  479. {
  480.     register struct StoredProperty    *sp;
  481.     register LONG            idx;
  482.     register int            ncolors;
  483.     register UBYTE            *rgb;
  484.     struct ViewPort            *vp = &scr->ViewPort;
  485.     LONG                r, g, b;
  486.     int                nc, ns;
  487.  
  488.     if (sp = FindProp (iff, ID_ILBM, ID_CMAP)) {
  489.         /*
  490.          * Compute the actual number of colors we need to convert.
  491.          */
  492.         nc = sp->sp_Size / 3;
  493.         ns = 1 << bmhd->nplanes;
  494.         ncolors = MIN (ns, nc);
  495.  
  496.         rgb = sp->sp_Data;
  497.         idx = 0;
  498.         while (ncolors--) {
  499.             r = *rgb++ >> 4;
  500.             g = *rgb++ >> 4;
  501.             b = *rgb++ >> 4;
  502.             SetRGB4 (vp, idx++, r, g, b);
  503.         }
  504.     }
  505. }
  506.  
  507. LONG
  508. loadbitmap (iff, bmhd, destmap)
  509. register struct IFFHandle    *iff;
  510. register struct BitMapHeader    *bmhd;
  511. struct BitMap            *destmap;
  512. {
  513.     register int        i, n, p;
  514.     register UWORD        *srcline, *destline;
  515.     struct BitMap        mapcopy;
  516.     UWORD            *linebuf;
  517.     LONG            error;
  518.     int            bodyw, bodyh, bodydepth, destw, desth,
  519.                 rows, mod;
  520.  
  521.     /*
  522.      * Check compression type.
  523.      */
  524.     if (bmhd->Compression != cmpNone &&
  525.         bmhd->Compression != cmpByteRun1) {
  526.         printf ("Unknown compression format type %d.\n",
  527.             bmhd->Compression);
  528.         return (1);
  529.     }
  530.  
  531.     CopyMem ((char *) destmap,
  532.          (char *) &mapcopy,
  533.          (LONG) sizeof (mapcopy));
  534.  
  535.     bodyw    = BPR (bmhd->w);
  536.     bodyh    = bmhd->h;
  537.     destw    = mapcopy.BytesPerRow;
  538.     desth    = mapcopy.Rows;
  539.     rows    = MIN (bodyh, desth);
  540.     mod    = destw - bodyw;
  541.     if (mod < 0)
  542.         mod = -mod;
  543.  
  544.     bodydepth = bmhd->nplanes;
  545.     if (bmhd->Masking == mskHasMask)
  546.         bodydepth++;
  547.  
  548.     /*
  549.      * Allocate a one-line buffer to load imagery in.  The line is
  550.      * then copied into the destination bitmap.  This seeming
  551.      * duplicity makes clipping loaded images easier.
  552.      */
  553.     if (!(linebuf = AllocMem ((LONG) bodyw * bodydepth, 0L))) {
  554.         puts ("Failed to allocate unpacking buffer");
  555.         return (1);
  556.     }
  557.  
  558.     /*
  559.      * Load the BODY into the allocated line buffer, then copy into
  560.      * the destination bitmap.
  561.      */
  562.     for (i = rows;  i--; ) {
  563.         if (error = loadline (iff,
  564.                       (UBYTE *) linebuf,
  565.                       bodyw,
  566.                       bodydepth,
  567.                       bmhd->Compression))
  568.             break;
  569.  
  570.         srcline = linebuf;
  571.         for (p = 0;  p < bmhd->nplanes;  p++) {
  572.             destline = (UWORD *) mapcopy.Planes[p];
  573.             n = (MIN (bodyw, destw)) >> 1;
  574.             while (n--)
  575.                 *destline++ = *srcline++;
  576.             if (bodyw > destw)
  577.                 srcline += mod >> 1;
  578.             mapcopy.Planes[p] += destw;
  579.         }
  580.     }
  581.  
  582.     FreeMem (linebuf, (LONG) bodyw * bodydepth);
  583.     return (error);
  584. }
  585.  
  586. /*
  587.  * This function reads a BODY in piecemeal i.e. it does lots of little short
  588.  * reads.  This is relatively slow, but saves on memory.
  589.  */
  590. LONG
  591. loadline (iff, buf, bpr, deep, cmptype)
  592. struct IFFHandle    *iff;
  593. register UBYTE        *buf;
  594. register int        bpr;        /*  Bytes per row  */
  595. int            deep, cmptype;
  596. {
  597.     if (cmptype == cmpNone) {    /* No compression */
  598.         register LONG    big = bpr * deep;
  599.  
  600.         if (ReadChunkBytes (iff, (APTR) buf, big) != big)
  601.             return (IFFERR_READ);
  602.     } else {
  603.         register int    i, remaining;
  604.         register UBYTE    *dest = buf;
  605.         BYTE        len;
  606.  
  607.         for (i = deep;  i--; ) {
  608.             remaining = bpr;
  609.             while (remaining > 0) {
  610.                 if (ReadChunkBytes
  611.                     (iff, (APTR) &len, 1L) != 1)
  612.                     return (IFFERR_READ);
  613.  
  614.                 if (len >= 0) {
  615.                     /*  Literal byte copy  */
  616.                     if ((remaining -= ++len) < 0)
  617.                         break;
  618.                     if (ReadChunkBytes
  619.                         (iff, (APTR) dest, (LONG) len)
  620.                         != len)
  621.                         return (IFFERR_READ);
  622.                     dest += len;
  623.  
  624.                 } else if (len != -128) {
  625.                     /*  Replication count  */
  626.                     register int    n;
  627.                     UBYTE        byte;
  628.  
  629.                     n = -len + 1;
  630.                     if ((remaining -= n) < 0)
  631.                         break;
  632.                     if (ReadChunkBytes
  633.                         (iff, (APTR) &byte, 1L) != 1)
  634.                         return (IFFERR_READ);
  635.                     while (--n >= 0)
  636.                         *dest++ = byte;
  637.                 }
  638.             }
  639.             if (remaining) {
  640.                 puts ("Image didn't decompress right.");
  641.                 return (1);
  642.             }
  643.         }
  644.         buf += bpr;
  645.     }
  646.     return (0);
  647. }
  648.  
  649.  
  650. /*
  651.  * File I/O functions which IFFParse will call.
  652.  *
  653.  * IFFParse uses 2.0 hook structures to implement custom streams.  In this
  654.  * case, we are creating a stdio stream, since unbuffered DOS I/O would be
  655.  * terribly slow.  See utility/hooks.h for more details on Hook mechanics.
  656.  *
  657.  * Upon entry, A0 contains a pointer to the hook, A2 is a pointer to your
  658.  * IFFHandle, and A1 is a pointer to a command packet, which tells you
  659.  * what to do.  A6 contains a pointer to IFFParseBase.  You may trash A0,
  660.  * A1, D0, and D1.  All other registers *MUST* be preserved.
  661.  *
  662.  * You return your error code in D0.  A return of 0 indicates success.  A
  663.  * non-zero return indicates an error.
  664.  *
  665.  * For this example, we are using Lattice's registerized parameter feature.
  666.  */
  667. static LONG __saveds __asm
  668. stdio_stream (
  669. register __a0 struct Hook        *hook,
  670. register __a2 struct IFFHandle        *iff,
  671. register __a1 struct IFFStreamCmd    *actionpkt
  672. )
  673. {
  674.     extern LONG    __builtin_getreg();
  675.  
  676.     register FILE    *stream;
  677.     register LONG    nbytes, error;
  678.     register UBYTE    *buf;
  679.     LONG        A6save;
  680.  
  681.     /*
  682.      * There is a bug somewhere in the Lattice stdio libraries.  Calling
  683.      * fread() trashes A6.  IFFParse demands that A6 be preserved during
  684.      * the call-back.  So I am using Lattice's builtin register
  685.      * manipulators to save and restore A6.
  686.      */
  687.     A6save = __builtin_getreg (14);
  688.  
  689.     stream    = (FILE *) iff->iff_Stream;
  690.     nbytes    = actionpkt->sc_NBytes;
  691.     buf    = (UBYTE *) actionpkt->sc_Buf;
  692.  
  693.     switch (actionpkt->sc_Command) {
  694.     case IFFCMD_READ:
  695.         /*
  696.          * IFFCMD_READ means read sc_NBytes from the stream and place
  697.          * it in the memory pointed to by sc_Buf.  Be aware that
  698.          * sc_NBytes may be larger than can be contained in an int.
  699.          * This is important if you plan on recompiling this for
  700.          * 16-bit ints, since fread() takes int arguments.
  701.          *
  702.          * Any error code returned will be remapped by IFFParse into
  703.          * IFFERR_READ.
  704.          */
  705.         error = fread (buf, 1, nbytes, stream) != nbytes;
  706.         break;
  707.  
  708.     case IFFCMD_WRITE:
  709.         /*
  710.          * IFFCMD_WRITE is analogous to IFFCMD_READ.
  711.          *
  712.          * Any error code returned will be remapped by IFFParse into
  713.          * IFFERR_WRITE.
  714.          */
  715.         error = fwrite (buf, 1, nbytes, stream) != nbytes;
  716.         break;
  717.  
  718.     case IFFCMD_SEEK:
  719.         /*
  720.          * IFFCMD_SEEK asks that you performs a seek relative to the
  721.          * current position.  sc_NBytes is a signed number,
  722.          * indicating seek direction (positive for forward, negative
  723.          * for backward).  sc_Buf has no meaning here.
  724.          *
  725.          * Any error code returned will be remapped by IFFParse into
  726.          * IFFERR_SEEK.
  727.          */
  728.         error = fseek (stream, nbytes, 1) == -1;
  729.         break;
  730.  
  731.     case IFFCMD_INIT:
  732.         /*
  733.          * IFFCMD_INIT means to prepare your stream for reading.
  734.          * This is used for certain streams that can't be read
  735.          * immediately upon opening, and need further preparation.
  736.          * This operation is allowed to fail;  the error code placed
  737.          * in D0 will be returned directly to the client.
  738.          *
  739.          * An example of such a stream is the clipboard.  The
  740.          * clipboard.device requires you to set the io_ClipID and
  741.          * io_Offset to zero before starting a read.  You would
  742.          * perform such a sequence here.  (Stdio files need no such
  743.          * preparation, so we simply return zero for success.)
  744.          */
  745.  
  746.     case IFFCMD_CLEANUP:
  747.         /*
  748.          * IFFCMD_CLEANUP means to terminate the transaction with
  749.          * the associated stream.  This is used for streams that
  750.          * can't simply be closed.  This operation is not allowed to
  751.          * fail;  any error returned will be ignored.
  752.          *
  753.          * An example of such a stream is (surprise!) the clipboard.
  754.          * It requires you to explicity end reads by CMD_READing
  755.          * past the end of a clip, and end writes by sending a
  756.          * CMD_UPDATE.  You would perform such a sequence here.
  757.          * (Again, stdio needs no such sequence.)
  758.          */
  759.         error = 0;
  760.         break;
  761.     }
  762.     /*  Fix A6  */
  763.     __builtin_putreg (14, A6save);
  764.     return (error);
  765. }
  766.  
  767. void
  768. initiffasstdio (iff)
  769. register struct IFFHandle *iff;
  770. {
  771.     static struct Hook    stdiohook = {
  772.         { NULL },
  773.         (ULONG (*)()) stdio_stream,
  774.         NULL,
  775.         NULL
  776.     };
  777.  
  778.     /*
  779.      * Initialize the IFF structure to point to the buffered I/O
  780.      * routines.  Unbuffered I/O is terribly slow.
  781.      */
  782.     InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &stdiohook);
  783. }
  784.  
  785.  
  786. /*
  787.  * IFF error printing function.
  788.  */
  789. LONG
  790. printIFFerr (error)
  791. LONG    error;
  792. {
  793.     /*
  794.      * English error messages for possible IFFERR_#? returns from various
  795.      * IFF routines.  To get the index into this array, take your IFFERR
  796.      * code, negate it, and subtract one.
  797.      *  idx = -error - 1;
  798.      */
  799.     static char    *errormsgs[] = {
  800.         "End of file (not an error).",
  801.         "End of context (not an error).",
  802.         "No lexical scope.",
  803.         "Insufficient memory.",
  804.         "Stream read error.",
  805.         "Stream write error.",
  806.         "Stream seek error.",
  807.         "File is corrupt.",
  808.         "IFF syntax error.",
  809.         "Not an IFF file.",
  810.         "Required hook vector missing.",
  811.         "Return to client.  You should never see this."
  812.     };
  813.  
  814.     if (error < 0)
  815.         printf ("IFF error: %s\n", errormsgs[(-error) - 1]);
  816.     return (error);
  817. }
  818.  
  819. /*
  820.  * Housekeeping.
  821.  */
  822. void
  823. openstuff ()
  824. {
  825.     if (!(IntuitionBase = OpenLibrary ("intuition.library", 33L)))
  826.         die ("Intuition won't open.  This is not good.");
  827.  
  828.     if (!(GfxBase = OpenLibrary ("graphics.library", 33L)))
  829.         die ("Graphics won't open.");
  830.  
  831.     if (!(IFFParseBase = OpenLibrary ("iffparse.library", 0L)))
  832.         die ("IFF parser library won't open.");
  833.  
  834.     if (!(iff = AllocIFF ()))
  835.         die ("Failed to create IFF control structure.");
  836.  
  837.     GetScreenData ((char *) &sensor,
  838.                (LONG) sizeof (sensor),
  839.                WBENCHSCREEN, NULL);
  840.  
  841.     /*  Convert to lo-res pixels.  */
  842.     if (sensor.ViewPort.Modes & HIRES)
  843.         sensor.Width >>= 1;
  844.     if (sensor.ViewPort.Modes & LACE)
  845.         sensor.Height >>= 1;
  846. }
  847.  
  848. void
  849. closestuff ()
  850. {
  851.     deletescreen ();
  852.     if (iff)        FreeIFF (iff);
  853.     if (IFFParseBase)    CloseLibrary (IFFParseBase);
  854.     if (GfxBase)        CloseLibrary (GfxBase);
  855.     if (IntuitionBase)    CloseLibrary (IntuitionBase);
  856. }
  857.  
  858. void
  859. die (str)
  860. char *str;
  861. {
  862.     puts (str);
  863.     closestuff ();
  864.     exit (20);
  865. }
  866.  
  867. /*
  868.  * Disable Lattice's default ^C trap.
  869.  */
  870. chkabort ()
  871. {
  872.     return (0);
  873. }
  874.  
  875. CXBRK ()
  876. {
  877.     return (0);
  878. }
  879.