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