home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / Misc / TRSICAT.LZX / CATS_CD2_TRSI / Reference_Library / Devices / modules / parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-21  |  11.1 KB  |  495 lines

  1. /*  
  2.  * parse.c - iffparse file IO support module
  3.  *   based on some of looki.c by Leo Schwab
  4.  *
  5.  * The filename for clipboard is -c or -cUnit as in -c0 -c1 etc. (default 0)
  6.  */
  7.  
  8. #include <exec/types.h>
  9.  
  10. #include "iffp/iff.h"
  11.  
  12. /* local function prototypes */
  13.  
  14. LONG stdio_stream(struct Hook *, struct IFFHandle *, struct IFFStreamCmd *);
  15.  
  16. UBYTE *omodes[2] = {"r","w"};
  17.  
  18.  
  19. /* openifile
  20.  *
  21.  * Passed a ParseInfo structure with a not-in-use IFFHandle, filename
  22.  *   ("-c" or -cUnit like "-c1" for clipboard), and IFF open mode
  23.  *   (IFFF_READ or IFFF_WRITE) opens file or clipboard for use with
  24.  *   iffparse.library support modules.
  25.  *
  26.  * Returns 0 for success or an IFFERR (libraries/iffparse.h)
  27.  */
  28.  
  29. LONG openifile(struct ParseInfo *pi, UBYTE *filename, ULONG iffopenmode)
  30. {
  31.     struct IFFHandle    *iff;
  32.     BOOL    cboard;
  33.     ULONG     unit = PRIMARY_CLIP;
  34.     LONG     error;
  35.  
  36.     if(!pi)            return(CLIENT_ERROR);
  37.         if(!(iff=pi->iff))    return(CLIENT_ERROR);
  38.  
  39.     cboard = (*filename == '-'  &&  filename[1] == 'c');
  40.      if(cboard && filename[2])    unit = atoi(&filename[2]);
  41.  
  42.     if (cboard)
  43.         {
  44.         /*
  45.          * Set up IFFHandle for Clipboard I/O.
  46.          */
  47.         pi->clipboard = TRUE;
  48.         if (!(iff->iff_Stream =
  49.                 (ULONG)OpenClipboard(unit)))
  50.             {
  51.             message("Clipboard open of unit %ld failed.\n",unit);
  52.             return(NOFILE);
  53.             }
  54.         InitIFFasClip(iff);
  55.         }
  56.     else
  57.         {
  58.         pi->clipboard = FALSE;
  59.         /*
  60.          * Set up IFFHandle for buffered stdio I/O.
  61.          */
  62.         if (!(iff->iff_Stream = (ULONG)
  63.            fopen(filename, omodes[iffopenmode & 1])))
  64.             {
  65.             message("%s: File open failed.\n",filename);
  66.             return(NOFILE);
  67.             }
  68.         else initiffasstdio(iff);
  69.         }
  70.  
  71.     D(bug("%s file opened: \n", cboard ? "[Clipboard]" : filename));
  72.  
  73.     pi->filename = filename;
  74.  
  75.     error=OpenIFF(iff, iffopenmode);
  76.  
  77.     pi->opened = error ? FALSE : TRUE;    /* currently open handle */
  78.  
  79.     D(bug("OpenIFF error = %ld\n",error));
  80.     return(error);
  81. }
  82.  
  83.  
  84. /* closeifile
  85.  *
  86.  * closes file or clipboard opened with openifile, and frees all
  87.  *   iffparse context parsed by parseifile.
  88.  *
  89.  * Note - You should closeifile as soon as possible if using clipboard
  90.  *   ("-c[n]").  You also need to closeifile if, for example, you wish to
  91.  *   reopen the file to write changes back out.  See the copychunks.c
  92.  *   module for routines which allow you clone the chunks iffparse has
  93.  *   gathered so that you can closeifile and still be able to modify and
  94.  *   write back out gathered chunks.
  95.  *   
  96.  */
  97.  
  98. void closeifile(struct ParseInfo *pi)
  99. {
  100. struct IFFHandle *iff;
  101.  
  102.     D(bug("closeifile:\n"));
  103.  
  104.     if(!pi)            return;
  105.         if(!(iff=pi->iff))    return;
  106.  
  107.     DD(bug("closeifile: About to CloseIFF if open, iff=$%lx, opened=%ld\n",
  108.             iff, pi->opened));
  109.  
  110.     if(pi->opened)    CloseIFF(iff);
  111.  
  112.     DD(bug("closeifile: About to close %s, stream=$%lx\n",
  113.             pi->clipboard ? "clipboard" : "file", iff->iff_Stream));
  114.     if(iff->iff_Stream)
  115.         {
  116.         if (pi->clipboard)
  117.            CloseClipboard((struct ClipHandle *)(iff->iff_Stream));
  118.         else
  119.            fclose ((FILE *)(iff->iff_Stream));
  120.         }
  121.  
  122.     iff->iff_Stream = NULL;
  123.     pi->clipboard = NULL;
  124.     pi->opened = NULL;
  125. }
  126.  
  127.  
  128. /* parseifile
  129.  *
  130.  * Passed a ParseInfo with an initialized and open IFFHandle,
  131.  *  grouptype (like ID_FORM), groupid (like ID_ILBM),
  132.  *  and TAG_DONE terminated longword arrays of type,id
  133.  *  for chunks to be grabbed, gathered, and stopped on
  134.  *  (like { ID_ILBM, ID_BMHD, ID_ILBM, ID_CAMG, TAG_DONE })
  135.  *  will parse an IFF file, grabbing/gathering and stopping
  136.  *  on specified chunk.
  137.  *
  138.  * Note - you can call getcontext() (to continue after a stop chunk) or
  139.  *  nextcontext() (after IFFERR_EOC, to parse next form in the same file)
  140.  *  if you wish to continue parsing the same IFF file.  If parseifile()
  141.  *  has to delve into a complex format to find your desired FORM, the
  142.  *  pi->hunt flag will be set.  This should be a signal to you that
  143.  *  you may not have the capability to simply modify and rewrite
  144.  *  the data you have gathered.
  145.  *
  146.  * Returns 0 for success else and IFFERR (libraries/iffparse.h)
  147.  */ 
  148.  
  149. LONG parseifile(pi,groupid,grouptype,propchks,collectchks,stopchks)
  150. struct    ParseInfo *pi;
  151. LONG groupid, grouptype;
  152. LONG *propchks, *collectchks, *stopchks;
  153. {
  154. struct IFFHandle *iff;    
  155. register struct ContextNode    *cn;
  156. LONG            error = 0L;
  157.  
  158.  
  159.         if(!(iff=pi->iff))    return(CLIENT_ERROR);
  160.  
  161.     if(!iff->iff_Stream)    return(IFFERR_READ);
  162.  
  163.     pi->hunt = FALSE;
  164.  
  165.     /*
  166.      * Declare property, collection and stop chunks.
  167.      */
  168.     if (propchks)
  169.       if (error = PropChunks (iff, propchks, chkcnt(propchks)))
  170.         return (error);
  171.     if (collectchks)
  172.       if (error =
  173.           CollectionChunks(iff, collectchks, chkcnt(collectchks)))
  174.         return (error);
  175.     if (stopchks)
  176.       if (error = StopChunks (iff, stopchks, chkcnt(stopchks)))
  177.         return (error);
  178.  
  179.     /*
  180.      * We want to stop at the end of an ILBM context.
  181.      */
  182.     if (grouptype)
  183.       if (error = StopOnExit (iff, grouptype, groupid))
  184.         return(error);
  185.  
  186.     /*
  187.      * Take first parse step to enter main chunk.
  188.      */
  189.     if (error = ParseIFF (iff, IFFPARSE_STEP))
  190.         return(error);
  191.  
  192.     /*
  193.      * Test the chunk info to see if simple form of type we want (ILBM).
  194.      */
  195.     if (!(cn = CurrentChunk (iff)))
  196.         {
  197.         /*
  198.          * This really should never happen.  If it does, it means
  199.          * our parser is broken.
  200.          */
  201.         message("Parsing error; no top chunk!\n");
  202.         return(NOFILE);
  203.         }
  204.  
  205.     if (cn->cn_ID != groupid  ||  cn->cn_Type != grouptype)
  206.         {
  207.         
  208.         D(bug("This is a(n) %.4s.%.4s.  Looking for embedded %.4s's...\n",
  209.           &cn->cn_Type, &cn->cn_ID, &grouptype));
  210.  
  211.         pi->hunt = TRUE;    /* Warning - this is a complex file */
  212.         }
  213.  
  214.     if(!error)    error = getcontext(iff);
  215.     return(error);
  216. }
  217.  
  218. /* chkcnt
  219.  *
  220.  * simply counts the number of chunk pairs (type,id) in array
  221.  */
  222. LONG chkcnt(LONG *taggedarray)
  223. {
  224. LONG k = 0;
  225.  
  226.     while(taggedarray[k] != TAG_DONE) k++;
  227.     return(k>>1);
  228. }
  229.  
  230.  
  231. /* currentchunkis
  232.  *
  233.  * returns the ID of the current chunk (like ID_CAMG)
  234.  */
  235. LONG currentchunkis(struct IFFHandle *iff, LONG type, LONG id)
  236. {
  237. register struct ContextNode    *cn;
  238. LONG result = 0;
  239.  
  240.     if (cn = CurrentChunk (iff))
  241.         {
  242.         if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
  243.         }
  244.     return(result);
  245. }
  246.  
  247.  
  248. /* contextis
  249.  *
  250.  * returns the enclosing context of the current chunk (like ID_ILBM)
  251.  */
  252. LONG contextis(struct IFFHandle *iff, LONG type, LONG id)
  253. {
  254. register struct ContextNode    *cn;
  255. LONG result = 0;
  256.  
  257.        if (cn = (CurrentChunk (iff)))
  258.            {
  259.            if (cn = (ParentChunk(cn)))
  260.                {
  261.                if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
  262.                }
  263.        }
  264.  
  265.     D(bug("This is a %.4s %.4s\n",&cn->cn_Type,&cn->cn_ID));
  266.  
  267.     return(result);
  268. }
  269.  
  270.  
  271. /* getcontext()
  272.  *
  273.  * Continues to gather the context which was specified to parseifile(),
  274.  *  stopping at specified stop chunk, or end of context, or EOF
  275.  *
  276.  * Returns 0 (stopped on a stop chunk)
  277.  *      or IFFERR_EOC (end of context, not an error)
  278.  *      or IFFER_EOF (end of file)
  279.  */
  280. LONG getcontext(iff)
  281. struct    IFFHandle *iff;
  282. {
  283.     LONG error = 0L;
  284.  
  285.     /* Based on our parse initialization,
  286.      * ParseIFF() will return on a stop chunk (error = 0)
  287.      * or end of context for an ILBM FORM (error = IFFERR_EOC)
  288.      * or end of file (error = IFFERR_EOF)
  289.      */
  290.     return(error = ParseIFF(iff, IFFPARSE_SCAN));
  291. }
  292.  
  293.  
  294. /* nextcontext
  295.  *
  296.  * If you have finished parsing and reading your context (IFFERR_EOC),
  297.  *   nextcontext will enter the next context contained in the file
  298.  *   and parse it.
  299.  *
  300.  * Returns 0 or an IFFERR such as IFFERR_EOF (end of file)
  301.  */
  302.  
  303. LONG nextcontext(iff)
  304. struct    IFFHandle *iff;
  305. {
  306.     LONG error = 0L;
  307.  
  308.     error = ParseIFF(iff, IFFPARSE_STEP);
  309.  
  310.     D(bug("nextcontext: Got through next step\n"));
  311.  
  312.     return(error);
  313. }
  314.  
  315.  
  316. /* findpropdata
  317.  *
  318.  * finds specified chunk parsed from IFF file, and
  319.  *   returns pointer to its sp_Data (or 0 for not found)
  320.  */
  321. UBYTE *findpropdata(iff, type, id)
  322. struct IFFHandle    *iff;
  323. LONG type, id;
  324.     {
  325.     register struct StoredProperty    *sp;
  326.  
  327.     if(sp = FindProp (iff, type, id)) return(sp->sp_Data);
  328.     return(0);
  329.     }
  330.  
  331.  
  332. /*
  333.  * File I/O hook functions which the IFF library will call.
  334.  * A return of 0 indicates success (no error).
  335.  *
  336.  * Iffparse.library calls this code via struct Hook and Hook.asm
  337.  */
  338. static LONG
  339. stdio_stream (hook, iff, actionpkt)
  340. struct Hook        *hook;
  341. struct IFFHandle    *iff;
  342. struct IFFStreamCmd    *actionpkt;
  343. {
  344.     register FILE    *stream;
  345.     register LONG    nbytes;
  346.     register int    actual;
  347.     register UBYTE    *buf;
  348.     long    len;
  349.  
  350.     stream    = (FILE *) iff->iff_Stream;
  351.     if(!stream)    return(1);
  352.  
  353.     nbytes    = actionpkt->sc_NBytes;
  354.     buf    = (UBYTE *) actionpkt->sc_Buf;
  355.  
  356.     switch (actionpkt->sc_Command) {
  357.     case IFFSCC_READ:
  358.         do {
  359.             actual = nbytes > 32767 ? 32767 : nbytes;
  360.             if ((len=fread (buf, 1, actual, stream)) != actual)
  361.                 break;
  362.             nbytes -= actual;
  363.             buf += actual;
  364.         } while (nbytes > 0);
  365.         return (nbytes ? IFFERR_READ : 0 );
  366.  
  367.     case IFFSCC_WRITE:
  368.         do {
  369.             actual = nbytes > 32767 ? 32767 : nbytes;
  370.             if ((len=fwrite (buf, 1, actual, stream)) != actual)
  371.                 break;
  372.             nbytes -= actual;
  373.             buf += actual;
  374.         } while (nbytes > 0);
  375.         return (nbytes ? IFFERR_WRITE : 0);
  376.  
  377.     case IFFSCC_SEEK:
  378.         return ((fseek (stream, nbytes, 1) == -1) ? IFFERR_SEEK : 0);
  379.  
  380.     default:
  381.         /*  No _INIT or _CLEANUP required.  */
  382.         return (0);
  383.     }
  384. }
  385.  
  386. /* initiffasstdio (ie. init iff as stdio)
  387.  *
  388.  * sets up hook callback for the file stream handler above
  389.  */
  390. void initiffasstdio (iff)
  391. struct IFFHandle *iff;
  392. {
  393.     extern LONG        HookEntry();
  394.     static struct Hook    stdiohook = {
  395.         { NULL },
  396.         (ULONG (*)()) HookEntry,
  397.         (ULONG (*)()) stdio_stream,
  398.         NULL
  399.     };
  400.  
  401.     /*
  402.      * Initialize the IFF structure to point to the buffered I/O
  403.      * routines.  Unbuffered I/O is terribly slow.
  404.      */
  405.     InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &stdiohook);
  406. }
  407.  
  408.  
  409. /*
  410.  * IFFerr
  411.  *
  412.  * Returns pointer to IFF Error string or NULL (no error)
  413.  */
  414. UBYTE *IFFerr(error)
  415. LONG    error;
  416. {
  417.     /*
  418.      * English error messages for possible IFFERR_#? returns from various
  419.      * IFF routines.  To get the index into this array, take your IFFERR
  420.      * code, negate it, and subtract one.
  421.      *  idx = -error - 1;
  422.      */
  423.     static UBYTE    *errormsgs[] = {
  424.         "End of file (not an error).",
  425.         "End of context (not an error).",
  426.         "No lexical scope.",
  427.         "Insufficient memory.",
  428.         "Stream read error.",
  429.         "Stream write error.",
  430.         "Stream seek error.",
  431.         "File is corrupt.",
  432.         "IFF syntax error.",
  433.         "Not an IFF file.",
  434.         "Required hook vector missing.",
  435.         "Return to client."
  436.     };
  437.     static UBYTE unknown[32];
  438.     static UBYTE client[] = "Client error";
  439.     static UBYTE nofile[] = "File not found or wrong type";
  440.  
  441.     if (error < 0)
  442.         {
  443.         return(errormsgs[(-error) - 1]);
  444.         }
  445.     else if(error = CLIENT_ERROR)
  446.         {
  447.         return(client);
  448.         }
  449.     else if(error = NOFILE)
  450.         {
  451.         return(nofile);
  452.         }
  453.     else if(error)
  454.         {
  455.         sprintf(unknown,"Unknown error %ld",error);
  456.         return(unknown);
  457.         }
  458.     else return(NULL);
  459. }
  460.  
  461.  
  462. /*
  463.  * PutCk
  464.  *
  465.  * Writes one chunk of data to an iffhandle
  466.  *
  467.  */
  468. long PutCk(struct IFFHandle *iff, long id, long size, void *data)
  469.     {
  470.     long error = 0, wlen;
  471.  
  472.     D(bug("PutCk: asked to push chunk \"%.4s\" ($%lx) length %ld\n",&id,id,size));
  473.  
  474.     if(error=PushChunk(iff, 0, id, size))
  475.     {
  476.     D(bug("PutCk: PushChunk of %.4s, error = %s, size = %ld\n",
  477.         id, IFFerr(error), id));
  478.     }
  479.     else
  480.     {
  481.     D(bug("PutCk: PushChunk of %.4s, error = %ld\n",&id, error));
  482.  
  483.     /* Write the actual data */
  484.     if((wlen = WriteChunkBytes(iff,data,size)) != size)
  485.         {
  486.         D(bug("WriteChunkBytes error: size = %ld, wrote %ld\n",size,wlen));
  487.         error = IFFERR_WRITE;
  488.         }
  489.     else error = PopChunk(iff);
  490.     D(bug("PutCk: After PopChunk - error = %ld\n",error));
  491.     }
  492.     return(error);
  493.     }
  494.  
  495.