home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 609b.lha / MandelSquare_v1.3 / Source.LZH / Source / SaveAnim / iffw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-06  |  7.4 KB  |  215 lines

  1. /*----------------------------------------------------------------------*
  2.  * IFFW.C  Support routines for writing IFF-85 files.          1/23/86
  3.  * (IFF is Interchange Format File.)
  4.  *
  5.  * By Jerry Morrison and Steve Shaw, Electronic Arts.
  6.  * This software is in the public domain.
  7.  *
  8.  * This version for the Commodore-Amiga computer.
  9.  *----------------------------------------------------------------------*/
  10. #include <iff/iff.h>
  11. #include <iff/gio.h>
  12. #include <stdio.h>
  13. /* ---------- IFF Writer -----------------------------------------------*/
  14.  
  15. /* A macro to test if a chunk size is definite, i.e. not szNotYetKnown.*/
  16. #define Known(size)   ( (size) != szNotYetKnown )
  17.  
  18. /* Yet another weird macro to make the source code simpler...*/
  19. #define IfIffp(expr)  {if (iffp == IFF_OKAY)  iffp = (expr);}
  20.  
  21. /* ---------- OpenWIFF -------------------------------------------------*/
  22. IFFP OpenWIFF(file, new0, limit)  BPTR file; GroupContext *new0; LONG limit; {
  23.     register GroupContext *new = new0;
  24.     register IFFP iffp = IFF_OKAY;
  25.  
  26.     new->parent       = NULL;
  27.     new->clientFrame  = NULL;
  28.     new->file         = file;
  29.     new->position     = 0;
  30.     new->bound        = limit;
  31.     new->ckHdr.ckID   = NULL_CHUNK;  /* indicates no current chunk */
  32.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  33.     return(iffp);
  34.     }
  35.  
  36. /* ---------- StartWGroup ----------------------------------------------*/
  37. IFFP StartWGroup(parent, groupType, groupSize, subtype, new)
  38.       GroupContext *parent, *new; ID groupType, subtype; LONG groupSize;  {
  39.     register IFFP iffp;
  40.  
  41.     iffp = PutCkHdr(parent, groupType, (long)groupSize);
  42.     IfIffp( IFFWriteBytes(parent, (BYTE *)&subtype, (long)sizeof(ID)) );
  43.     IfIffp( OpenWGroup(parent, new) );
  44.     return(iffp);
  45.     }
  46.  
  47. /* ---------- OpenWGroup -----------------------------------------------*/
  48. IFFP OpenWGroup(parent0, new0)  GroupContext *parent0, *new0; {
  49.     register GroupContext *parent = parent0;
  50.     register GroupContext *new    = new0;
  51.     register LONG ckEnd;
  52.     register IFFP iffp = IFF_OKAY;
  53.  
  54.     new->parent       = parent;
  55.     new->clientFrame  = parent->clientFrame;
  56.     new->file         = parent->file;
  57.     new->position     = parent->position;
  58.     new->bound        = parent->bound;
  59.     new->ckHdr.ckID   = NULL_CHUNK;
  60.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  61.  
  62.     if ( Known(parent->ckHdr.ckSize) ) {
  63.     ckEnd = new->position + ChunkMoreBytes(parent);
  64.     if ( new->bound == szNotYetKnown || new->bound > ckEnd )
  65.         new->bound = ckEnd;
  66.     };
  67.  
  68.     if ( parent->ckHdr.ckID == NULL_CHUNK || /* not currently writing a chunk*/
  69.      IS_ODD(new->position) ||
  70.          (Known(new->bound) && IS_ODD(new->bound)) )
  71.     iffp = CLIENT_ERROR;
  72.     return(iffp);
  73.     }
  74.  
  75. /* ---------- CloseWGroup ----------------------------------------------*/
  76. IFFP CloseWGroup(old0)  GroupContext *old0; {
  77.     register GroupContext *old = old0;
  78.     IFFP iffp = IFF_OKAY;
  79.  
  80.     if ( old->ckHdr.ckID != NULL_CHUNK )  /* didn't close the last chunk */
  81.     iffp = CLIENT_ERROR;
  82.     else if ( old->parent == NULL ) {      /* top level file context */
  83.     if (GWriteFlush(old->file) < 0)  iffp = DOS_ERROR;
  84.     }
  85.     else {                  /* update parent context */
  86.     old->parent->bytesSoFar += old->position - old->parent->position;
  87.     old->parent->position = old->position;
  88.     };
  89.     return(iffp);
  90.     }
  91.  
  92. /* ---------- EndWGroup ------------------------------------------------*/
  93. IFFP EndWGroup(old)  GroupContext *old;  {
  94.     register GroupContext *parent = old->parent;
  95.     register IFFP iffp;
  96.  
  97.     iffp = CloseWGroup(old);
  98.     IfIffp( PutCkEnd(parent) );
  99.     return(iffp);
  100.     }
  101.  
  102. /* ---------- PutCk ----------------------------------------------------*/
  103. IFFP PutCk(context, ckID, ckSize, data)
  104.       GroupContext *context; ID ckID; LONG ckSize; BYTE *data; {
  105.     register IFFP iffp = IFF_OKAY;
  106.  
  107.     if ( ckSize == szNotYetKnown )
  108.     iffp = CLIENT_ERROR;
  109.     IfIffp( PutCkHdr(context, ckID, ckSize) );
  110.     IfIffp( IFFWriteBytes(context, data, ckSize) );
  111.     IfIffp( PutCkEnd(context) );
  112.     return(iffp);
  113.     }
  114.  
  115. /* ---------- PutCkHdr -------------------------------------------------*/
  116. IFFP PutCkHdr(context0, ckID, ckSize)
  117.       GroupContext *context0;  ID ckID;  LONG ckSize; {
  118.     register GroupContext *context = context0;
  119.     LONG minPSize = sizeof(ChunkHeader); /* physical chunk >= minPSize bytes*/
  120.  
  121.     /* CLIENT_ERROR if we're already inside a chunk or asked to write
  122.      * other than one FORM, LIST, or CAT at the top level of a file */
  123.     /* Also, non-positive ID values are illegal and used for error codes.*/
  124.     /* (We could check for other illegal IDs...)*/
  125.     if ( context->ckHdr.ckID != NULL_CHUNK  ||  ckID <= 0 )
  126.     return(CLIENT_ERROR);
  127.     else if (context->parent == NULL)  {
  128.     switch (ckID)  {
  129.         case FORM:  case LIST:  case CAT:  break;
  130.         default: return(CLIENT_ERROR);
  131.         }
  132.     if (context->position != 0)
  133.         return(CLIENT_ERROR);
  134.     }
  135.  
  136.     if ( Known(ckSize) ) {
  137.     if ( ckSize < 0 )
  138.         return(CLIENT_ERROR);
  139.     minPSize += ckSize;
  140.     };
  141.     if ( Known(context->bound)  &&
  142.          context->position + minPSize > context->bound )
  143.     return(CLIENT_ERROR);
  144.  
  145.     context->ckHdr.ckID   = ckID;
  146.     context->ckHdr.ckSize = ckSize;
  147.     context->bytesSoFar   = 0;
  148.     if (0 >
  149.     GWrite(context->file, (BYTE *)&context->ckHdr
  150.                 , (long)sizeof(ChunkHeader))) return(DOS_ERROR);
  151.     context->position += sizeof(ChunkHeader);
  152.     return(IFF_OKAY);
  153.     }
  154.  
  155. /* ---------- IFFWriteBytes ---------------------------------------------*/
  156. IFFP IFFWriteBytes(context0, data, nBytes)
  157.       GroupContext *context0;  BYTE *data;  LONG nBytes; {
  158.     register GroupContext *context = context0;
  159.  
  160.     if ( context->ckHdr.ckID == NULL_CHUNK  ||    /* not in a chunk */
  161.      nBytes < 0  ||                /* negative nBytes */
  162.      (Known(context->bound)  &&        /* overflow context */
  163.         context->position + nBytes > context->bound)  ||
  164.      (Known(context->ckHdr.ckSize)  &&       /* overflow chunk */
  165.         context->bytesSoFar + nBytes > context->ckHdr.ckSize) )
  166.     return(CLIENT_ERROR);
  167.  
  168.     if (0 > GWrite(context->file, data, nBytes))
  169.     return(DOS_ERROR);
  170.  
  171.     context->bytesSoFar += nBytes;
  172.     context->position   += nBytes;
  173.     return(IFF_OKAY);
  174.     }
  175.  
  176. /* ---------- PutCkEnd -------------------------------------------------*/
  177. IFFP PutCkEnd(context0)  GroupContext *context0; {
  178.     register GroupContext *context = context0;
  179.     WORD zero = 0;    /* padding source */
  180.  
  181.     if ( context->ckHdr.ckID == NULL_CHUNK )  /* not in a chunk */
  182.     return(CLIENT_ERROR);
  183.  
  184.     if ( context->ckHdr.ckSize == szNotYetKnown ) {
  185.     /* go back and set the chunk size to bytesSoFar */
  186.     if ( 0 >
  187. GSeek(context->file, (-((long)context->bytesSoFar + (long)sizeof(LONG)))
  188.                       , (long)OFFSET_CURRENT) ||
  189.          0 >
  190. GWrite(context->file, (BYTE *)&context->bytesSoFar, (long)sizeof(LONG))  ||
  191.          0 >
  192. GSeek(context->file, (long)context->bytesSoFar, (long)OFFSET_CURRENT)  )
  193.         return(DOS_ERROR);
  194.     }
  195.     else {  /* make sure the client wrote as many bytes as planned */
  196.     if ( context->ckHdr.ckSize != context->bytesSoFar )
  197.         return(CLIENT_ERROR);
  198.     };
  199.  
  200.     /* Write a pad byte if needed to bring us up to an even boundary.
  201.      * Since the context end must be even, and since we haven't
  202.      * overwritten the context, if we're on an odd position there must
  203.      * be room for a pad byte. */
  204.     if ( IS_ODD(context->bytesSoFar) ) {
  205.     if ( 0 > GWrite(context->file, (BYTE *)&zero, 1L) ) {
  206.            return(DOS_ERROR);
  207.         }
  208.     context->position += 1;
  209.     };
  210.  
  211.     context->ckHdr.ckID   = NULL_CHUNK;
  212.     context->ckHdr.ckSize = context->bytesSoFar = 0;
  213.     return(IFF_OKAY);
  214.     }
  215.