/* Ilbm.library C application, PicInfo.c: Set your editor's TAB width to 3 cc +p IFFinfo.c as -cd IlbmInterface.asm ln -o IFFinfo IFFinfo.o IlbmInterface.o -lcl32 This program can only be run from the CLI. It takes 1 arg, the name of a file. This program will then print information about the file. For ILBMs and ANIMs, it will print out information from the BHMD(s) such as image width, height, depth, etc. For other IFF files, it will simply print the chunk IDs as it encounters them. For ANIMs, it will total the number of "frames" (ILBMs) in the file. Note that the library automatically dives into LISTS and CATS on our behalf. We don't even have to know that we are inside of a LIST or CAT. This is an example of using the library's mid-level routine LoadILBM() with our own FORM and PROP handlers instead of lib's default routines. This is the way to go if you need an ANIM reader or some non-ILBM reader/writer. Note that if our FORMHandler wasn't interested in ILBMs or ANIMs, we wouldn't need an ILBMFrame, and would use LoadIFF() instead of LoadILBM(). */ #include "math.h" #include "functions.h" /* Manx C declarations */ #include "exec/tasks.h" #include "exec/types.h" #include "exec/memory.h" #include "libraries/dos.h" #include "libraries/dosextens.h" /* The ilbm lib C INCLUDE file */ #include "ILBM_Lib.h" /*-------------------------------defines---------------------------------*/ IFFP myForm(); IFFP myProp(); /* Data for the Dissidents ILBM library */ struct ILBMBase *ILBMBase=0L; struct ILBMFrame myILBMFrame; /* Whenever we plan on parsing an ILBM or ANIM, we need an ILBMFrame */ /* Data for our program */ struct FileHandle *fp = 0; SHORT numFrames = -1; /* To count the # of frames in an ANIM */ UBYTE handled_anim = 0; /* To tell main() that we found an ANIM */ /*------------------------------start of main()----------------------------*/ main( argc, argv ) LONG argc; UBYTE *argv[]; { IFFP Result; /* LoadILBM() and LoadIFF() need a Vectors structure */ Vectors myVectors; /* We expect the filename for the first arg. */ if( argc != 2 ) { printf("USAGE: IFFinfo filename\n"); exit(); } /* Open the ILBM lib */ if( (ILBMBase=(struct ILBMBase *)OpenLibrary("ilbm.library", 0L)) == NULL ) { printf("Need the dissidents ilbm.library on boot disk\n"); exit(); } /* Note that we are using the lib's middle level functions so that we can install our own handlers for each encountered group and context. Also, we can parse any IFF FORM, not just ILBMs and ANIMs using this level. Unlike the lib's high level ILBM functions LoadIFFToWindow() and SaveWindowToIFF(), the mid level functions don't open the IFF file for us. We are going to install our own function, myForm(), as the routine which the library calls whenever it encounters a FORM ID. Our function, myProp() will be called for non-ILBM PROPS. (Remember, the library automatically handles all ILBM PROPS by parsing info into a PropILBMFrame.) We "install" these routines by setting up the appropriate fields in our Vectors structure. Let's do all this now. */ /* Open the IFF File */ fp = Open( argv[1], MODE_OLDFILE ); if (fp) { /* Setup the Vectors structure. (i.e. "install" myForm() and myProp()) */ myVectors.PROPhandler = myProp; myVectors.FORMhandler = myForm; myVectors.CHUNKhandler = 0; myVectors.NonILBMhandler = 0; /* Don't care about CHUNKhandler or NonILBMhandler as long as we have our own FORMhandler. */ myILBMFrame.iUserFlags=0; /* Start parsing the file */ Result=LoadILBM( fp, &myVectors, &myILBMFrame ); /* O.K. we're back. Did we successfully parse as much as we wanted? Well, our FORM routine should have returned IFF_OKAY if we parsed the entire file. Otherwise, myForm, myProp, or an internal library routine knocked us out by returning some other IFFP error code. Let's get an informative error msg to display. */ /* If some error, get the IFFP error message and print it */ if( Result != IFF_OKAY ) { puts( GetIFFPMsg( Result ) ); } else /* If it was an ANIM we inspected, show the # of frames */ { if( handled_anim ) printf("Number of Frames = %d", numFrames+1); } /* Close the IFF File */ Close(fp); } else printf( "Couldn't open %s. \n", argv[1]); printf("\n"); /* Close ILBM lib */ if( ILBMBase ) CloseLibrary( ILBMBase ); exit(); } /* end of main() */ /*========= LoadILBM() or LoadIFF() calls me when it finds a FORM ==========*/ IFFP myForm( chunkID, context, vectors, frame, proplist ) PROPList *proplist; struct ILBMFrame *frame; Vectors *vectors; GroupContext *context; ID chunkID; { register IFFP code = IFF_OKAY; register ULONG propf; BitMapHeader bmhdr; /* Print the FORM ID */ printf("========= FORM %c%c%c%c =========\n", (char) ((chunkID>>24L) & 0x7F), (char) ((chunkID>>16L) & 0x7F), (char) ((chunkID>>8) & 0x7F), (char) (chunkID & 0x7F) ); /* --------------------- ANIM HEADER ------------------------- */ /* If an ANIM, reset our frame count and ANIM flags of iUserFlags. Then parse the "frames" (imbedded ILBMs) of the ANIM. Note that GetF1ChunkHdr actually calls our myForm() routine for each imbedded ILBM "frame of animation" (i.e. this function is recursive). */ if (chunkID == ID_ANIM) { /* set ANIMFLAG of iUserFlags to indicate that we're in an ANIM */ frame->iUserFlags |= ANIMFLAG; /* clear HANDLED_ANIM to indicate that we aren't successful yet */ handled_anim = 0; numFrames = -1; /* first frame number will be 0 */ /* Parse each frame of the ANIM */ while (code >= 0) { code = GetF1ChunkHdr(context); } /* If we didn't get END_MARK back, then an error */ if (code == END_MARK) { /* set HANDLED_ANIM to indicate that we successfully handled the ANIM */ handled_anim = 1; code = IFF_OKAY; /* So that we continue parsing any more FORMs in the file */ } } /* ---------------------- ILBM FORMS (ANIM "frames") -------------------- */ if (chunkID == ID_ILBM ) { /* Parse an ILBM or an ANIM "frame" (which is also an ILBM) */ /* If there was an ILBM PROP for this group, copy the PROPFrame to our ILBMFrame. Note: SearchPROP() can return any kind of frame. Here, it is an ILBMFrame since chunkID == ID_ILBM. If we needed to reference anything in the returned pointer, we would have to recast it as an (ILBMFrame *). */ if( !(propf = SearchPROP( chunkID, proplist )) ) CopyILBMProp( propf, frame ); if( frame->iUserFlags & ANIMFLAG ) { ++numFrames; /* 1 more "frame" */ printf( "--- Frame #%d ---\n", numFrames+1 ); } while( code >= 0 ) /* Negative numbers are errors, 0 means "ok, continue" and positive numbers are IFF chunk IDs */ { /* Move to the start of the next chunk */ code = GetFChunkHdr( context ); if (code > 0 ) /* Here's a chunk ID. If this were a REAL program, we'd probably check to see if this is a chunk that we want to parse. If so, we could get the chunksize from the context structure, read the chunk into memory, and do something with the data. For example, like what I did with the BMHD chunk. Or maybe like this: bytes = ChunkMoreBytes( context ); if( !( memptr = AllocMem( bytes, 0L ) )) { code = IFFReadBytes( bytes, context, memptr ); } */ { printf(" %c%c%c%c\n", (char) ( (code>>24L) & 0x7F), (char) ( (code>>16L) & 0x7F), (char) ( (code>>8) & 0x7F), (char) ( code & 0x7F) ); if( code == ID_BMHD ) { /* Print out info about the image */ code = GetBMHD(context, &bmhdr); if( code == IFF_OKAY ) { printf(" width=%d, height=%d, depth=%d\n", bmhdr.w, bmhdr.h, bmhdr.nPlanes); } } } } } /* --------------------- Non-ILBM FORMS --------------------- */ else { /* A REAL program would normally search the PROPList for any frames of the same type, and if found extract needed info from it. See notes in myProp() */ while( code >= 0 ) { code = GetF1ChunkHdr(context); if (code > 0) /* Here's a chunk ID. If this were a REAL program, we'd probably do something useful with it. */ { printf(" %c%c%c%c\n", (char) ( (code>>24L) & 0x7F), (char) ( (code>>16L) & 0x7F), (char) ( (code>>8) & 0x7F), (char) ( code & 0x7F) ); } } } /* As long as we rtn IFF_OKAY, the library will continue parsing the IFF file (until it gets to the end). If we rtn any other value, the library will return us back to main() from LoadILBM() with that value. For example, if we return IFF_DONE, we would return from LoadILBM with IFF_DONE. Note: the library routines GetFChunkHdr and GetF1ChunkHdr will return END_MARK when there's no more chunks in this FORM. In that case, we should know whether we found what we wanted in this FORM. If we did, we return IFF_OKAY to continue parsing the next FORM (we may be inside of a LIST or CAT), or IFF_DONE if we want to get out with what we've got. If we didn't find what we want, we would return IFF_OKAY to continue parsing. In this example, we're looking for everything, so we always return IFF_OKAY when GetFChunkHdr or GetF1ChunkHdr returns END_MARK. */ if (code == END_MARK) { /* Print a double-spaced line inbetween forms */ puts("=============================\n"); code = IFF_OKAY; } return( code ); } /*========= LoadILBM() or LoadIFF() calls me when it finds a PROP ==========*/ IFFP myProp( chunkID, propID, context, vectors, frame, proplist ) PROPList *proplist; struct ILBMFrame *frame; Vectors *vectors; GroupContext *context; ID propID; ID chunkID; { /* We only hear about non-ILBM PROPS. If this were a REAL program, we would probably allocate some PROPFrame that we defined for the passed propID (an SMUSPropFrame for an ID_SMUS maybe?). Then we would parse the PROP's chunks just like in the FORMhandler, storing info in this new PROPFrame. Later, in our FORMHandler, we search the PROPList for the appropriate ID and retrieve the info. The library automatically updates the PROPList when it gets to the end of an IFF group so that you don't have to keep track of which level you're at and which PROPS affect which chunks. Also, the library frees all PROPFrames that you allocate with GetPROPStruct() by the time we return to main. */ /* Print the PROP ID */ printf(" PROP %c%c%c%c\n", (char) ((chunkID>>24L) & 0x7F), (char) ((chunkID>>16L) & 0x7F), (char) ((chunkID>>8) & 0x7F), (char) (chunkID & 0x7F) ); return( IFF_OKAY ); }