home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 523b.lha / Drawmap_v2.25d / Sources.LZH / Sources / iffw.c < prev    next >
C/C++ Source or Header  |  1991-06-10  |  8KB  |  214 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.  
  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.  
  23. IFFP OpenWIFF(file, new, limit)  BPTR file; GroupContext *new; LONG limit; {
  24.     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.  
  34.     if (0 > Seek(file, 0, OFFSET_BEGINNING))    /* Go to start of the file.*/
  35.         iffp = DOS_ERROR;
  36.     else if ( Known(limit) && IS_ODD(limit) )
  37.         iffp = CLIENT_ERROR;
  38.     return(iffp);
  39.     }
  40.  
  41. /* ---------- StartWGroup ----------------------------------------------*/
  42. IFFP StartWGroup(parent, groupType, groupSize, subtype, new)
  43.       GroupContext *parent, *new; ID groupType, subtype; LONG groupSize;  {
  44.     IFFP iffp;
  45.  
  46.     iffp = PutCkHdr(parent, groupType, groupSize);
  47.     IfIffp( IFFWriteBytes(parent, (BYTE *)&subtype, sizeof(ID)) );
  48.     IfIffp( OpenWGroup(parent, new) );
  49.     return(iffp);
  50.     }
  51.  
  52. /* ---------- OpenWGroup -----------------------------------------------*/
  53. IFFP OpenWGroup(parent, new)  GroupContext *parent, *new; {
  54.     LONG ckEnd;
  55.     IFFP iffp = IFF_OKAY;
  56.  
  57.     new->parent       = parent;
  58.     new->clientFrame  = parent->clientFrame;
  59.     new->file         = parent->file;
  60.     new->position     = parent->position;
  61.     new->bound        = parent->bound;
  62.     new->ckHdr.ckID   = NULL_CHUNK;
  63.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  64.  
  65.     if ( Known(parent->ckHdr.ckSize) ) {
  66.         ckEnd = new->position + ChunkMoreBytes(parent);
  67.         if ( new->bound == szNotYetKnown || new->bound > ckEnd )
  68.             new->bound = ckEnd;
  69.         };
  70.  
  71.     if ( parent->ckHdr.ckID == NULL_CHUNK || /* not currently writing a chunk*/
  72.          IS_ODD(new->position) ||
  73.          (Known(new->bound) && IS_ODD(new->bound)) )
  74.         iffp = CLIENT_ERROR;
  75.     return(iffp);
  76.     }
  77.  
  78. /* ---------- CloseWGroup ----------------------------------------------*/
  79. IFFP CloseWGroup(old)  GroupContext *old; {
  80.     IFFP iffp = IFF_OKAY;
  81.  
  82.     if ( old->ckHdr.ckID != NULL_CHUNK )  /* didn't close the last chunk */
  83.         iffp = CLIENT_ERROR;
  84.     else if ( old->parent == NULL ) {     /* top level file context */
  85.         if (GWriteFlush(old->file) < 0)  iffp = DOS_ERROR;
  86.         }
  87.     else {                                /* update parent context */
  88.         old->parent->bytesSoFar += old->position - old->parent->position;
  89.         old->parent->position = old->position;
  90.         };
  91.     return(iffp);
  92.     }
  93.  
  94. /* ---------- EndWGroup ------------------------------------------------*/
  95. IFFP EndWGroup(old)  GroupContext *old;  {
  96.     register GroupContext *parent = old->parent;
  97.     register IFFP iffp;
  98.  
  99.     iffp = CloseWGroup(old);
  100.     IfIffp( PutCkEnd(parent) );
  101.     return(iffp);
  102.     }
  103.  
  104. /* ---------- PutCk ----------------------------------------------------*/
  105. IFFP PutCk(context, ckID, ckSize, data)
  106.       GroupContext *context; ID ckID; LONG ckSize; BYTE *data; {
  107.     register IFFP iffp = IFF_OKAY;
  108.  
  109.     if ( ckSize == szNotYetKnown )
  110.         iffp = CLIENT_ERROR;
  111.     IfIffp( PutCkHdr(context, ckID, ckSize) );
  112.     IfIffp( IFFWriteBytes(context, data, ckSize) );
  113.     IfIffp( PutCkEnd(context) );
  114.     return(iffp);
  115.     }
  116.  
  117. /* ---------- PutCkHdr -------------------------------------------------*/
  118. IFFP PutCkHdr(context, ckID, ckSize)
  119.       GroupContext *context;  ID ckID;  LONG ckSize; {
  120.     LONG minPSize = sizeof(ChunkHeader); /* physical chunk >= minPSize bytes*/
  121.  
  122.     /* CLIENT_ERROR if we're already inside a chunk or asked to write
  123.      * other than one FORM, LIST, or CAT at the top level of a file */
  124.     /* Also, non-positive ID values are illegal and used for error codes.*/
  125.     /* (We could check for other illegal IDs...)*/
  126.     if ( context->ckHdr.ckID != NULL_CHUNK  ||  ckID <= 0 )
  127.         return(CLIENT_ERROR);
  128.     else if (context->parent == NULL)  {
  129.         switch (ckID)  {
  130.             case FORM:  case LIST:  case CAT:  break;
  131.             default: return(CLIENT_ERROR);
  132.             }
  133.         if (context->position != 0)
  134.             return(CLIENT_ERROR);
  135.         }
  136.  
  137.     if ( Known(ckSize) ) {
  138.         if ( ckSize < 0 )
  139.             return(CLIENT_ERROR);
  140.         minPSize += ckSize;
  141.         };
  142.     if ( Known(context->bound)  &&
  143.          context->position + minPSize > context->bound )
  144.         return(CLIENT_ERROR);
  145.  
  146.     context->ckHdr.ckID   = ckID;
  147.     context->ckHdr.ckSize = ckSize;
  148.     context->bytesSoFar   = 0;
  149.     if (0 >
  150.         GWrite(context->file, (BYTE *)&context->ckHdr, sizeof(ChunkHeader))
  151.         )
  152.         return(DOS_ERROR);
  153.     context->position += sizeof(ChunkHeader);
  154.     return(IFF_OKAY);
  155.     }
  156.  
  157. /* ---------- IFFWriteBytes ---------------------------------------------*/
  158. IFFP IFFWriteBytes(context, data, nBytes)
  159.       GroupContext *context;  BYTE *data;  LONG nBytes; {
  160.  
  161.     if ( context->ckHdr.ckID == NULL_CHUNK  ||  /* not in a chunk */
  162.          nBytes < 0  ||                         /* negative nBytes */
  163.          (Known(context->bound)  &&             /* overflow context */
  164.             context->position + nBytes > context->bound)  ||
  165.          (Known(context->ckHdr.ckSize)  &&      /* overflow chunk */
  166.             context->bytesSoFar + nBytes > context->ckHdr.ckSize) )
  167.         return(CLIENT_ERROR);
  168.  
  169.     if (0 > GWrite(context->file, data, nBytes))
  170.         return(DOS_ERROR);
  171.  
  172.     context->bytesSoFar += nBytes;
  173.     context->position   += nBytes;
  174.     return(IFF_OKAY);
  175.     }
  176.  
  177. /* ---------- PutCkEnd -------------------------------------------------*/
  178. IFFP PutCkEnd(context)  GroupContext *context; {
  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, -(context->bytesSoFar + sizeof(LONG)), OFFSET_CURRENT) ||
  188.              0 >
  189. GWrite(context->file, (BYTE *)&context->bytesSoFar, sizeof(LONG))  ||
  190.              0 >
  191. GSeek(context->file, context->bytesSoFar, OFFSET_CURRENT)  )
  192.             return(DOS_ERROR);
  193.         }
  194.     else {  /* make sure the client wrote as many bytes as planned */
  195.         if ( context->ckHdr.ckSize != context->bytesSoFar )
  196.             return(CLIENT_ERROR);
  197.         };
  198.  
  199.     /* Write a pad byte if needed to bring us up to an even boundary.
  200.      * Since the context end must be even, and since we haven't
  201.      * overwritten the context, if we're on an odd position there must
  202.      * be room for a pad byte. */
  203.     if ( IS_ODD(context->bytesSoFar) ) {
  204.         if ( 0 > GWrite(context->file, (BYTE *)&zero, 1) )
  205.             return(DOS_ERROR);
  206.         context->position += 1;
  207.         };
  208.  
  209.     context->ckHdr.ckID   = NULL_CHUNK;
  210.     context->ckHdr.ckSize = context->bytesSoFar = 0;
  211.     return(IFF_OKAY);
  212.     }
  213.  
  214.