home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 004.lha / Dpaintx_source / iffr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-03-02  |  10.3 KB  |  321 lines

  1. /*----------------------------------------------------------------------*
  2.  * IFFR.C  Support routines for reading IFF-85 files.          11/11/85
  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.  * modified by Carolyn Scheppner
  11.  *    expects iff.h in include/iff/
  12.  *    defined OFFSET_BEGINING
  13.  *----------------------------------------------------------------------*/
  14. #include "exec/types.h"
  15. #include "libraries/dos.h"
  16. #include "iff/iff.h"
  17.  
  18. #ifndef OFFSET_BEGINNING
  19. #define OFFSET_BEGINNING OFFSET_BEGINING
  20. #endif
  21.  
  22. /* ---------- Read -----------------------------------------------------*/
  23.  
  24. /* ---------- OpenRIFF --------------------------------------------------*/
  25. IFFP OpenRIFF(file0, new0, clientFrame)
  26.    BPTR file0;   GroupContext *new0;  ClientFrame *clientFrame; {
  27.     register BPTR file = file0;
  28.     register GroupContext *new = new0;
  29.     IFFP iffp = IFF_OKAY;
  30.  
  31.     new->parent       = NULL;      /* "whole file" has no parent.*/
  32.     new->clientFrame  = clientFrame;
  33.     new->file         = file;
  34.     new->position     = 0;
  35.     new->ckHdr.ckID   = new->subtype    = NULL_CHUNK;
  36.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  37.  
  38.     /* Set new->bound. AmigaDOS specific code.*/
  39.     if (file <= 0)   return(NO_FILE);
  40.     Seek(file, 0, OFFSET_END);         /* Seek to end of file.*/
  41.     new->bound = Seek(file, 0, OFFSET_CURRENT);   /* Pos'n == #bytes in file.*/
  42.     if (new->bound < 0)   return(DOS_ERROR);   /* DOS being absurd.*/
  43.     Seek(file, 0, OFFSET_BEGINNING);      /* Go to file start.*/
  44.     /* Would just do this if Amiga DOS maintained fh_End: */
  45.     /* new->bound = (FileHandle *)BADDR(file)->fh_End; */
  46.  
  47.     if ( new->bound < sizeof(ChunkHeader) )
  48.    iffp = NOT_IFF;
  49.     return(iffp);
  50.     }
  51.  
  52. /* ---------- OpenRGroup -----------------------------------------------*/
  53. IFFP OpenRGroup(parent0, new0)   GroupContext *parent0, *new0; {
  54.     register GroupContext *parent = parent0;
  55.     register GroupContext *new    = new0;
  56.     IFFP iffp = IFF_OKAY;
  57.  
  58.     new->parent       = parent;
  59.     new->clientFrame  = parent->clientFrame;
  60.     new->file         = parent->file;
  61.     new->position     = parent->position;
  62.     new->bound        = parent->position + ChunkMoreBytes(parent);
  63.     new->ckHdr.ckID   = new->subtype    = NULL_CHUNK;
  64.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  65.  
  66.     if ( new->bound > parent->bound  ||  IS_ODD(new->bound) )
  67.    iffp = BAD_IFF;
  68.     return(iffp);
  69.     }
  70.  
  71. /* ---------- CloseRGroup -----------------------------------------------*/
  72. IFFP CloseRGroup(context)   GroupContext *context; {
  73.     register LONG position;
  74.  
  75.     if (context->parent == NULL) {
  76.    }  /* Context for whole file.*/
  77.     else {
  78.    position = context->position;
  79.    context->parent->bytesSoFar += position - context->parent->position;
  80.    context->parent->position = position;
  81.    }
  82.     return(IFF_OKAY);
  83.     }
  84.  
  85. /* ---------- SkipFwd --------------------------------------------------*/
  86. /* Skip over bytes in a context. Won't go backwards.*/
  87. /* Updates context->position but not context->bytesSoFar.*/
  88. /* This implementation is AmigaDOS specific.*/
  89. IFFP SkipFwd(context, bytes)   GroupContext *context;  LONG bytes; {
  90.     IFFP iffp = IFF_OKAY;
  91.  
  92.     if (bytes > 0) {
  93.    if (-1 == Seek(context->file, bytes, OFFSET_CURRENT))
  94.        iffp = BAD_IFF;   /* Ran out of bytes before chunk complete.*/
  95.    else
  96.        context->position += bytes;
  97.    }
  98.     return(iffp);
  99.     }
  100.  
  101. /* ---------- GetChunkHdr ----------------------------------------------*/
  102. ID GetChunkHdr(context0)   GroupContext *context0;  {
  103.     register GroupContext *context = context0;
  104.     register IFFP iffp;
  105.     LONG remaining;
  106.  
  107.     /* Skip remainder of previous chunk & padding. */
  108.     iffp = SkipFwd(context,
  109.    ChunkMoreBytes(context) + IS_ODD(context->ckHdr.ckSize));
  110.     CheckIFFP();
  111.  
  112.     /* Set up to read the new header. */
  113.     context->ckHdr.ckID = BAD_IFF;   /* Until we know it's okay, mark it BAD.*/
  114.     context->subtype    = NULL_CHUNK;
  115.     context->bytesSoFar = 0;
  116.  
  117.     /* Generate a psuedo-chunk if at end-of-context. */
  118.     remaining = context->bound - context->position;
  119.     if (remaining == 0) {
  120.    context->ckHdr.ckSize = 0;
  121.    context->ckHdr.ckID   = END_MARK;
  122.    }
  123.  
  124.     /* BAD_IFF if not enough bytes in the context for a ChunkHeader.*/
  125.     else if (sizeof(ChunkHeader) > remaining) {
  126.    context->ckHdr.ckSize = remaining;
  127.    }
  128.  
  129.     /* Read the chunk header (finally). */
  130.     else {
  131.         switch (Read(context->file, &context->ckHdr, sizeof(ChunkHeader))) {
  132.        case -1: return(context->ckHdr.ckID = DOS_ERROR);
  133.        case 0:  return(context->ckHdr.ckID = BAD_IFF);
  134.        }
  135.  
  136.    /* Check: Top level chunk must be LIST or FORM or CAT. */
  137.    if (context->parent == NULL)
  138.        switch(context->ckHdr.ckID) {
  139.       case FORM:  case LIST:  case CAT:  break;
  140.       default:    return(context->ckHdr.ckID = NOT_IFF);
  141.       }
  142.  
  143.    /* Update the context. */
  144.    context->position += sizeof(ChunkHeader);
  145.    remaining         -= sizeof(ChunkHeader);
  146.  
  147.    /* Non-positive ID values are illegal and used for error codes.*/
  148.    /* We could check for other illegal IDs...*/
  149.    if (context->ckHdr.ckID <= 0)
  150.         context->ckHdr.ckID = BAD_IFF;
  151.  
  152.    /* Check: ckSize negative or larger than # bytes left in context? */
  153.    else if (context->ckHdr.ckSize < 0  ||
  154.        context->ckHdr.ckSize > remaining) {
  155.        context->ckHdr.ckSize = remaining;
  156.        context->ckHdr.ckID   = BAD_IFF;
  157.        }
  158.  
  159.    /* Automatically read the LIST, FORM, PROP, or CAT subtype ID */
  160.    else switch (context->ckHdr.ckID) {
  161.        case LIST:  case FORM:  case PROP:  case CAT:  {
  162.       iffp = IFFReadBytes(context,
  163.                 (BYTE *)&context->subtype,
  164.                 sizeof(ID));
  165.       if (iffp != IFF_OKAY)
  166.           context->ckHdr.ckID = iffp;
  167.       break; }
  168.        }
  169.  
  170.    }
  171.     return(context->ckHdr.ckID);
  172.     }
  173.  
  174. /* ---------- IFFReadBytes ---------------------------------------------*/
  175. IFFP IFFReadBytes(context, buffer, nBytes)
  176.     GroupContext *context;   BYTE *buffer;   LONG nBytes; {
  177.     register IFFP iffp = IFF_OKAY;
  178.  
  179.     if (nBytes < 0)
  180.    iffp = CLIENT_ERROR;
  181.     else if (nBytes > ChunkMoreBytes(context))
  182.    iffp = SHORT_CHUNK;
  183.     else if (nBytes > 0)
  184.    switch ( Read(context->file, buffer, nBytes) ) {
  185.        case -1: {iffp = DOS_ERROR; break; }
  186.        case 0:  {iffp = BAD_IFF;   break; }
  187.        default: {
  188.       context->position   += nBytes;
  189.       context->bytesSoFar += nBytes;
  190.       }
  191.        }
  192.  
  193.     return(iffp);
  194.     }
  195.  
  196. /* ---------- SkipGroup ------------------------------------------------*/
  197. IFFP SkipGroup(context)  GroupContext *context;  {
  198.     }   /* Nothing to do, thanks to GetChunkHdr */
  199.  
  200. /* ---------- ReadIFF --------------------------------------------------*/
  201. IFFP ReadIFF(file, clientFrame)  BPTR file;  ClientFrame *clientFrame;  {
  202.     /*CompilerBug register*/ IFFP iffp;
  203.     GroupContext context;
  204.  
  205. #ifdef DEBUGDALE
  206.    printf("call OpenRIFF\n");
  207. #endif
  208.     iffp = OpenRIFF(file, &context);
  209.     context.clientFrame = clientFrame;
  210.  
  211. #ifdef DEBUGDALE
  212.    printf("do switch\n");
  213. #endif
  214.     if (iffp == IFF_OKAY)
  215.    switch (iffp = GetChunkHdr(&context)) {
  216.        case FORM: { iffp = (*clientFrame->getForm)(&context); break; }
  217.        case LIST: { iffp = (*clientFrame->getList)(&context); break; }
  218.        case CAT : { iffp = (*clientFrame->getCat )(&context); break; }
  219.        /* default: Includes IFF_DONE, BAD_IFF, NOT_IFF... */
  220.        }
  221.  
  222. #ifdef DEBUGDALE
  223.    printf("closergroup\n");
  224. #endif
  225.     CloseRGroup(&context);
  226.  
  227.     if (iffp > 0)      /* Make sure we don't return an ID.*/
  228.    iffp = NOT_IFF;      /* GetChunkHdr should've caught this.*/
  229. #ifdef DEBUGDALE
  230.    printf("return now from ReadIFF\n");
  231. #endif
  232.     return(iffp);
  233.     }
  234.  
  235. /* ---------- ReadIList ------------------------------------------------*/
  236. IFFP ReadIList(parent, clientFrame)
  237.     GroupContext *parent;  ClientFrame *clientFrame; {
  238.     GroupContext listContext;
  239.     IFFP iffp;
  240.     BOOL propOk = TRUE;
  241.  
  242.     iffp = OpenRGroup(parent, &listContext);
  243.     CheckIFFP();
  244.  
  245.     /* One special case test lets us handle CATs as well as LISTs.*/
  246.     if (parent->ckHdr.ckID == CAT)
  247.    propOk = FALSE;
  248.     else
  249.    listContext.clientFrame = clientFrame;
  250.  
  251.     do {
  252.    switch (iffp = GetChunkHdr(&listContext)) {
  253.        case PROP: {
  254.       if (propOk)
  255.           iffp = (*clientFrame->getProp)(&listContext);
  256.       else
  257.           iffp = BAD_IFF;
  258.       break;
  259.       }
  260.        case FORM: { iffp = (*clientFrame->getForm)(&listContext); break; }
  261.        case LIST: { iffp = (*clientFrame->getList)(&listContext); break; }
  262.        case CAT : { iffp = (*clientFrame->getCat )(&listContext); break; }
  263.        /* default: Includes END_MARK, IFF_DONE, BAD_IFF, NOT_IFF... */
  264.        }
  265.    if (listContext.ckHdr.ckID != PROP)
  266.        propOk = FALSE;   /* No PROPs allowed after this point.*/
  267.    } while (iffp == IFF_OKAY);
  268.  
  269.     CloseRGroup(&listContext);
  270.  
  271.     if (iffp > 0)   /* Only chunk types above are allowed in a LIST/CAT.*/
  272.    iffp = BAD_IFF;
  273.     return(iffp == END_MARK ? IFF_OKAY : iffp);
  274.     }
  275.  
  276. /* ---------- ReadICat -------------------------------------------------*/
  277. /* By special arrangement with the ReadIList implement'n, this is trivial.*/
  278. IFFP ReadICat(parent)  GroupContext *parent;  {
  279.     return( ReadIList(parent, NULL) );
  280.     }
  281.  
  282. /* ---------- GetFChunkHdr ---------------------------------------------*/
  283. ID GetFChunkHdr(context)   GroupContext *context; {
  284.     register ID id;
  285.  
  286.     id = GetChunkHdr(context);
  287.     if (id == PROP)
  288.    context->ckHdr.ckID = id = BAD_IFF;
  289.     return(id);
  290.     }
  291.  
  292. /* ---------- GetF1ChunkHdr ---------------------------------------------*/
  293. ID GetF1ChunkHdr(context)   GroupContext *context; {
  294.     register ID id;
  295.     register ClientFrame *clientFrame = context->clientFrame;
  296.  
  297.     switch (id = GetChunkHdr(context))  {
  298.    case PROP: { id = BAD_IFF; break; }
  299.    case FORM: { id = (*clientFrame->getForm)(context); break; }
  300.    case LIST: { id = (*clientFrame->getList)(context); break; }
  301.    case CAT : { id = (*clientFrame->getCat )(context); break; }
  302.    /* Default: let the caller handle other chunks */
  303.    }
  304.     return(context->ckHdr.ckID = id);
  305.     }
  306.  
  307. /* ---------- GetPChunkHdr ---------------------------------------------*/
  308. ID GetPChunkHdr(context)   GroupContext *context; {
  309.     register ID id;
  310.  
  311.     id = GetChunkHdr(context);
  312.     switch (id) {
  313.    case LIST:  case FORM:  case PROP:  case CAT:  {
  314.        id = context->ckHdr.ckID = BAD_IFF;
  315.        break; }
  316.    }
  317.     return(id);
  318.     }
  319.  
  320.  
  321.