/********************************************************************** * * jiff.c Jim Kent's iff - ilbm reader * * This is the (sortof) short (sortof) simple no-frills IFF reader * to get something out of DPaint, Images, or the Animator. It * works well with the Aztec C compiler. It should work with Lattice * but you never know until you try it. I haven't. * * I've included a simple main program. This is just to make it * stand alone. Since amiga screen initializations are massive, all * it does as is is read it into a BitMap, and then free up the BitMap. * Should crash it if it's gonna crash though. * * The main interface to this is through the routine read_iff(filename). * This returns a ILBM_info structure-pointer on success, and NULL on * failure. It cleans up after itself on failure. * * I hope you will find this useful and easy to use. Please forgive * my funky indentation style? Well at least I'm consistent! * * To demonstrate what a nice guy I am even though I'm far from wild * about the IFF standard I'm placing this in the public domain. When * you remove the DEBUG and PARANOID definitions the code is only * 1536 bytes long. * * -Jim Kent April 22, 1986 ************************************************************************/ #include #include #include #include #include #include "jiff.h" /*this is the normal state of software development. Seriously undefine this to make it shut up about errors and reduce code size half way through beta testing... */ #define PARANOID static struct ILBM_info *read_ilbm(), *read_body(); /* OK this code is almost re-entrant. Pass this guy from above to make it really re-entrant. (Why do you need a reentrant ILBM reader though?? Maybe for Dale ... ) */ static struct ILBM_info root_info; /*static so get initialized to zero*/ #ifdef PARANOID /* a little paranoid routine that say's where we got before EOF */ static void iff_truncated(where) int where; { printf("ILBM truncated %d\n", where); free_planes(&root_info.bitmap); } /* iff_truncated */ #endif PARANOID struct ILBM_info *read_iff(name, just_colors) char *name; short just_colors; { struct ILBM_info *info = &root_info; FILE *file; struct form_chunk chunk; if ((file = fopen(name, "r") ) == 0){ #ifdef PARANOID printf("couldn't Open %s to read\n", name); #endif PARANOID return(NULL); } if ( fread(&chunk, sizeof(struct form_chunk), 1, file) != 1){ #ifdef PARANOID iff_truncated(0); #endif PARANOID fclose(file); return(NULL); } if (chunk.fc_type.b4_type != FORM){ #ifdef PARANOID printf("not a FORM - %s\n", name); #endif PARANOID fclose(file); return(NULL); } if (chunk.fc_subtype.b4_type != ILBM){ #ifdef PARANOID printf("FORM not an ILBM - %s\n", name); #endif PARANOID fclose(file); return(NULL); } #ifdef DEBUG printf("FORM %ld ILBM\n", chunk.fc_length); #endif DEBUG info = read_ilbm(file, info, chunk.fc_length - sizeof(chunk), just_colors); fclose(file); #ifdef DEBUG printf("info = %lx\n", info); #endif DEBUG return(info); } /* read_iff */ static struct ILBM_info *read_ilbm(file, info, length, just_colors) FILE *file; struct ILBM_info *info; long length; short just_colors; { struct iff_chunk chunk; int i; long read_in = 0; int got_header = FALSE; /*to make sure gots the header first*/ int got_cmap = FALSE; /*make sure get cmap before "BODY" */ /* make sure the Planes are all NULL so can free up memory easily * on error abort */ for (i=0; i<8; i++) info->bitmap.Planes[i] = NULL; while (read_in < length){ if (fread(&chunk, sizeof(chunk), 1, file) != 1){ #ifdef PARANOID iff_truncated(1); #endif PARANOID return(NULL); } switch (chunk.iff_type.b4_type){ case BMHD: #ifdef DEBUG printf("\tBMHD %ld\n", chunk.iff_length); #endif DEBUG if (fread(&info->header, sizeof(info->header), 1, file) != 1){ #ifdef PARANOID iff_truncated(2); #endif PARANOID return(NULL); } got_header = TRUE; break; case CMAP: #ifdef DEBUG printf("\tCMAP %ld\n", chunk.iff_length); #endif DEBUG if (!got_header){ #ifdef PARANOID printf("CMAP befor BMHD\n"); #endif PARANOID return(NULL); } if (chunk.iff_length <= 3*MAXCOL ){ if (fread(info->cmap, (int)chunk.iff_length, 1, file) != 1){ #ifdef PARANOID iff_truncated(3); #endif PARANOID return(NULL); } }else{ #ifdef PARANOID printf("warning, more than %d colors in ILBM CMAP\n", MAXCOL); #endif PARANOID if (fread(info->cmap, 3*MAXCOL, 1, file) != 1){ #ifdef PARANOID iff_truncated(4); #endif PARANOID return(NULL); } bit_bucket(file, chunk.iff_length - sizeof(3*MAXCOL)); } got_cmap = TRUE; if (just_colors) return(info); break; case BODY: if (!got_cmap){ #ifdef PARANOID printf("BODY before CMAP\n"); #endif PARANOID return(NULL); } #ifdef DEBUG printf("\tBODY %ld\n", chunk.iff_length); #endif DEBUG return( read_body(file, info, chunk.iff_length) ); case GRAB: /*ignore documented but unwanted types*/ case DEST: case SPRT: case CAMG: case CRNG: case CCRT: bit_bucket(file, chunk.iff_length); break; default: /*squawk about unknown types if PARANOID */ #ifdef PARANOID printf("\t unk type %lx of b4_type\n", chunk.iff_type.b4_type); #endif PARANOID } /* switch */ read_in += chunk.iff_length + sizeof(chunk); } /* while */ #ifdef PARANOID printf("no BODY in ILBM\n"); #endif PARANOID return(NULL); } /* read_ilbm */ static struct ILBM_info *read_body(file, info, length) FILE *file; register struct ILBM_info *info; long length; { struct ILBM_header *header; struct BitMap *bm; int i, j; int rlength; int plane_offset; #ifdef DEBUG printf("read_body( %lx %lx %ld)\n", file, info, length); #endif DEBUG #ifdef PARANOID /* when paranoid do a little error checking first ... fail fast! */ if (info->header.nPlanes > 8){ printf("Whoa, woe Dale only speaks 8 planes boy, not %d\n", info->header.nPlanes); return(NULL); } #endif PARANOID /* ok a little more error checking */ if (info->header.compression != 0 && info->header.compression != 1){ #ifdef PARANOID printf("unrecognized compression type %d\n", info->header.compression); #endif PARANOID return(NULL); } /*set up the bitmap part that doesn't involve memory allocation first - hey this part does get done, and let's be optimistic...*/ info->bitmap.BytesPerRow = line_bytes(info->header.w); info->bitmap.Rows = info->header.h; info->bitmap.Depth = info->header.nPlanes; info->bitmap.Flags = info->bitmap.pad = 0; rlength = info->bitmap.Rows * info->bitmap.BytesPerRow; for (i=0; iheader.nPlanes; i++){ if ((info->bitmap.Planes[i] = ralloc(rlength)) == NULL){ #ifdef PARANOID printf("couldn't alloc plane %d in read_body\n",i); #endif PARANOID free_planes( &info->bitmap ); return(NULL); } } /* for i */ plane_offset = 0; for (i=0; ibitmap.Rows; i++){ /* this test should be in the inner loop for shortest code, * in the outer loop for greatest speed, so sue me I compromised. */ if (info->header.compression == 0){ for (j = 0; j < info->bitmap.Depth; j++){ if ( fread(info->bitmap.Planes[j] + plane_offset, info->bitmap.BytesPerRow, 1, file) != 1){ #ifdef PARANOID iff_truncated(6); #endif PARANOID free_planes( &info->bitmap); return(NULL); } } /* for j */ }else{ register char *dest, value; register int so_far, count; /*how much have unpacked so far*/ for (j = 0; j < info->bitmap.Depth; j++){ so_far = info->bitmap.BytesPerRow; dest = (char *)info->bitmap.Planes[j] + plane_offset; while (so_far > 0){ if ( (value = getc(file)) == 128){ #ifdef DEBUG printf("NOP\n"); #endif DEBUG }else if (value > 0){ count = (int)value + 1; so_far -= count; if ( fread(dest, count, 1, file) != 1){ #ifdef PARANOID iff_truncated(7); #endif PARANOID free_planes( &info->bitmap); return(NULL); } dest += count; }else{ count = (int)-value + 1; so_far -= count; value = getc(file); while (--count >= 0) /*this is fastest loop in C */ *dest++ = value; } /* if value */ } /* while */ if (so_far != 0){ #ifdef PARANOID printf("compression quite screwed up, aborting %d\n", so_far); #endif PARANOID free_planes( &info->bitmap); return(NULL); } /* if so_far */ } /* for j */ } /* if info->header.compression */ plane_offset += info->bitmap.BytesPerRow; } /* for i */ return(info); } /* read_body */ void free_planes(bmap) register struct BitMap *bmap; { PLANEPTR plane; long length; short i; length = bmap->BytesPerRow * bmap->Rows; for (i=0; i<8; i++) if ( (plane = bmap->Planes[i]) != NULL) rfree(plane, length); } /* free_planes */