/** ReadPict.c ************************************************************** * * Read an ILBM raster image file. 01/07/85. * * By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts. * This software is in the public domain. * * USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF READER. * * The IFF reader portion is essentially a recursive-descent parser. * This program will look into a CAT or LIST to find a FORM ILBM, but it * won't look inside another FORM type for a nested FORM ILBM. ****************************************************************************/ #define LOCAL /* static */ /* #include "intuall.h" */ #include #include #include "ilbm.h" #include "readpict.h" /* This example's max number of planes in a bitmap. Could use MaxAmDepth. */ #define EXDepth 5 #define maxColorReg (1<subtype != ID_ILBM) return(IFF_OKAY); /* just continue scaning the file */ ilbmFrame = *(ILBMFrame *)parent->clientFrame; iffp = OpenRGroup(parent, &formContext); CheckIFFP(); do { iffp = GetFChunkHdr(&formContext); if (iffp == ID_BMHD) { ilbmFrame.foundBMHD = TRUE; iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr); } else if (iffp == ID_CMAP) { ilbmFrame.nColorRegs = maxColorReg; /* we have room for this many */ iffp = GetCMAP( &formContext, (WORD *)&ilbmFrame.colorMap, &ilbmFrame.nColorRegs); } else if (iffp == ID_BODY) { if (!ilbmFrame.foundBMHD) return(BAD_FORM); /* No BMHD chunk! */ nPlanes = MIN(ilbmFrame.bmHdr.nPlanes, EXDepth); InitBitMap( gBM, nPlanes, (long)ilbmFrame.bmHdr.w, (long)ilbmFrame.bmHdr.h); plsize = RowBytes(ilbmFrame.bmHdr.w) * ilbmFrame.bmHdr.h; /* Allocate all planes contiguously. Not really necessary, * but it avoids writing code to back-out if only enough memory * for some of the planes. * WARNING: Don't change this without changing the code that * Frees these planes. */ if (gBM->Planes[0] = (PLANEPTR)(*gAllocator)(nPlanes * plsize)) { for (i = 1; i < nPlanes; i++) gBM->Planes[i] = (PLANEPTR) gBM->Planes[0] + plsize*i; iffp = GetBODY( &formContext, gBM, NULL, &ilbmFrame.bmHdr, bodyBuffer, (long)bufSz); if (iffp == IFF_OKAY) iffp = IFF_DONE; /* Eureka */ *giFrame = ilbmFrame; /* Copy fields to client's frame.*/ } else iffp = CLIENT_ERROR; /* not enough RAM for the bitmap */ } else if (iffp == END_MARK) iffp = BAD_FORM; } while (iffp >= IFF_OKAY); /* loop if valid ID of ignored chunk or a * subroutine returned IFF_OKAY (no errors).*/ if (iffp != IFF_DONE) return(iffp); /* If we get this far, there were no errors. */ CloseRGroup(&formContext); return(iffp); } /** Notes on extending GetFoILBM ******************************************** * * To read more kinds of chunks, just add clauses to the switch statement. * To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to * the switch statement in GetPrILBM, too. * * To read a FORM type that contains a variable number of data chunks--e.g. * a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with * an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK * case do whatever cleanup you need. * ****************************************************************************/ /** GetPrILBM() ************************************************************* * * Called via ReadPicture to handle every PROP encountered in an IFF file. * Reads PROPs ILBM and skips all others. * ****************************************************************************/ #if Fancy IFFP GetPrILBM(parent) GroupContext *parent; { /*compilerBug register*/ IFFP iffp; GroupContext propContext; ILBMFrame *ilbmFrame = (ILBMFrame *)parent->clientFrame; if (parent->subtype != ID_ILBM) return(IFF_OKAY); /* just continue scaning the file */ iffp = OpenRGroup(parent, &propContext); CheckIFFP(); do switch (iffp = GetPChunkHdr(&propContext)) { case ID_BMHD: { ilbmFrame->foundBMHD = TRUE; iffp = GetBMHD(&propContext, &ilbmFrame->bmHdr); break; } case ID_CMAP: { ilbmFrame->nColorRegs = maxColorReg; /* we have room for this many */ iffp = GetCMAP( &propContext, (WORD *)&ilbmFrame->colorMap, &ilbmFrame->nColorRegs); break; } } while (iffp >= IFF_OKAY); /* loop if valid ID of ignored chunk or a * subroutine returned IFF_OKAY (no errors).*/ CloseRGroup(&propContext); return(iffp == END_MARK ? IFF_OKAY : iffp); } #endif /** GetLiILBM() ************************************************************* * * Called via ReadPicture to handle every LIST encountered in an IFF file. * ****************************************************************************/ #if Fancy IFFP GetLiILBM(parent) GroupContext *parent; { ILBMFrame newFrame; /* allocate a new Frame */ newFrame = *(ILBMFrame *)parent->clientFrame; /* copy parent frame */ return( ReadIList(parent, (ClientFrame *)&newFrame) ); } #endif /** ReadPicture() *********************************************************** * * Read a picture from an IFF file, given a file handle open for reading. * Allocates BitMap using (*Allocator)(). * ****************************************************************************/ IFFP ReadPicture(file, bm, iFrame, Allocator) LONG file; struct BitMap *bm; ILBMFrame *iFrame; /* Top level "client frame".*/ UBYTE *(*Allocator)(); /* Allocation procedure which only requires * size parameter. That is, no flags parameter. * Must be in Chip memory, for bitmap data.*/ { IFFP iffp = IFF_OKAY; #if Fancy iFrame->clientFrame.getList = GetLiILBM; iFrame->clientFrame.getProp = GetPrILBM; #else iFrame->clientFrame.getList = SkipGroup; iFrame->clientFrame.getProp = SkipGroup; #endif iFrame->clientFrame.getForm = GetFoILBM; iFrame->clientFrame.getCat = ReadICat ; /* Initialize the top-level client frame's property settings to the * program-wide defaults. This example just records that we haven't read * any BMHD property or CMAP color registers yet. For the color map, that * means the default is to leave the machine's color registers alone. * If you want to read a property like GRAB, init it here to (0, 0). */ iFrame->foundBMHD = FALSE; iFrame->nColorRegs = 0; gAllocator = Allocator; gBM = bm; giFrame = iFrame; /* Store a pointer to the client's frame in a global variable so that * GetFoILBM can update client's frame when done. Why do we have so * many frames & frame pointers floating around causing confusion? * Because IFF supports PROPs which apply to all FORMs in a LIST, * unless a given FORM overrides some property. * When you write code to read several FORMs, * it is essential to maintain a frame at each level of the syntax * so that the properties for the LIST don't get overwritten by any * properties specified by individual FORMs. * We decided it was best to put that complexity into this one-FORM example, * so that those who need it later will have a useful starting place. */ iffp = ReadIFF(file, (ClientFrame *)iFrame); return(iffp); }