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