/********************************************************************** * * 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. * * 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! * * [ I didn't forgive it. I changed it -- Peter ] * * 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 * * Cleaned it up and added CAMG chunk handler. Also, fixed indentation * and removed static reference to root_info, allowing multiple images * to be loaded. * * -Peter da Silva September 27, 1987 ************************************************************************/ #include #include #include #include #include #include #include "jiff.h" /* #define DEBUG */ #define PARANOID #ifdef DEBUG # define D(x) x #else # define D(x) #endif #ifdef PARANOID # define P(x) x #else # define P(x) #endif static struct ILBM_info *read_ilbm(), *read_body(); static struct ILBM_info *root_info; void free_image(); #define CHIP (MEMF_PUBLIC|MEMF_CHIP) #ifdef PARANOID /* a little paranoid routine that say's where we got before EOF */ static void iff_truncated(info,where) struct ILBM_info *info; int where; { printf("ILBM truncated %d\n", where); free_image(info); } #else #define iff_truncated(i,w) free_image(i) #endif struct ILBM_info * read_iff(name, just_colors) char *name; short just_colors; { struct ILBM_info *info; FILE *file; struct form_chunk chunk; info = 0; if((file = fopen(name, "r") ) == 0) { P(printf("couldn't Open %s to read\n", name)); return(NULL); } if( fread(&chunk, sizeof(struct form_chunk), 1, file) != 1) { iff_truncated(NULL, 0); fclose(file); return(NULL); } if(chunk.fc_type.b4_type != FORM) { P(printf("not a FORM - %s\n", name)); fclose(file); return(NULL); } if(chunk.fc_subtype.b4_type != ILBM) { P(printf("FORM not an ILBM - %s\n", name)); fclose(file); return(NULL); } D(printf("FORM %ld ILBM\n", chunk.fc_length)); root_info = AllocMem(sizeof(struct ILBM_info), MEMF_PUBLIC); if(!root_info) { P(printf("Can't allocate ILBM_info.\n")); fclose(file); return NULL; } info = read_ilbm(file, root_info, chunk.fc_length - sizeof(chunk), just_colors); if(info) { if(info->viewmode & HAM) info->colors = 16; if(info->header.h > 298) info->viewmode |= LACE; if(info->header.w > 376) info->viewmode |= HIRES; } fclose(file); D(printf("info = %lx\n", info)); return(info); } 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" */ info->viewmode = 0L; /*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) { iff_truncated(info, 1); return(NULL); } switch (chunk.iff_type.b4_type) { case BMHD: D(printf("\tBMHD %ld\n", chunk.iff_length)); if(fread(&info->header, sizeof(info->header), 1, file) != 1) { iff_truncated(info, 2); return(NULL); } got_header = TRUE; break; case CMAP: D(printf("\tCMAP %ld\n", chunk.iff_length)); if(!got_header) { printf("CMAP befor BMHD\n"); free_image(info); return(NULL); } if(chunk.iff_length <= 3*MAXCOL ) { if(fread(info->cmap, (int)chunk.iff_length, 1, file) != 1) { iff_truncated(info, 3); return(NULL); } info->colors = chunk.iff_length/3; } else { P(printf("warning, more than %d colors in ILBM CMAP\n", MAXCOL)); if(fread(info->cmap, 3*MAXCOL, 1, file) != 1) { iff_truncated(info, 4); return(NULL); } bit_bucket(file, chunk.iff_length - 3*MAXCOL); info->colors = MAXCOL; } got_cmap = TRUE; if(just_colors) return(info); break; case CAMG: D(printf("\tCAMG %ld\n", chunk.iff_length)); if(chunk.iff_length <= sizeof(long) ) { if(fread(&info->viewmode, (int)chunk.iff_length, 1, file) != 1) { iff_truncated(info, 8); return(NULL); } } else { P(printf("warning, more than viewport mode in ILBM CMAP\n")); if(fread(&info->viewmode, sizeof(long), 1, file) != 1) { iff_truncated(info, 9); return(NULL); } bit_bucket(file, chunk.iff_length - sizeof(long)); } break; case BODY: if(!got_cmap) { P(printf("BODY before CMAP\n")); free_image(info); return(NULL); } D(printf("\tBODY %ld\n", chunk.iff_length)); return( read_body(file, info, chunk.iff_length) ); default: #ifdef PARANOID printf("Unknown type "); printf("%c", (chunk.iff_type.b4_type>>24)&0x7F); printf("%c", (chunk.iff_type.b4_type>>16)&0x7F); printf("%c", (chunk.iff_type.b4_type>>8)&0x7F); printf("%c", (chunk.iff_type.b4_type)&0x7F); printf(" of b4_type\n"); #endif PARANOID case GRAB: /*ignore documented but unwanted types*/ case DEST: case SPRT: case CRNG: case CCRT: bit_bucket(file, chunk.iff_length); break; } read_in += chunk.iff_length + sizeof(chunk); } P(printf("no BODY in ILBM\n")); free_image(info); return(NULL); } 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; D(printf("read_body( %lx %lx %ld)\n", file, info, length)); #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); free_image(info); return(NULL); } #endif PARANOID /* ok a little more error checking */ if(info->header.compression != 0 && info->header.compression != 1) { P(printf("unrecognized compression type %d\n", info->header.compression)); free_image(info); 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] = AllocMem(rlength, CHIP)) == NULL) { P(printf("couldn't alloc plane %d in read_body\n",i)); free_image(info); return(NULL); } } 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) { iff_truncated(info, 6); return(NULL); } } } 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) { D(printf("NOP\n")); } else if(value > 0) { count = (int)value + 1; so_far -= count; if( fread(dest, count, 1, file) != 1) { iff_truncated(info, 7); 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(so_far != 0) { P(printf("compression quite screwed up, aborting %d\n", so_far)); free_image(info); return(NULL); } } } plane_offset += info->bitmap.BytesPerRow; } return(info); } void free_image(info) struct ILBM_info *info; { if(info) { free_planes(&info->bitmap); FreeMem(info, sizeof(struct ILBM_info)); } } 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) FreeMem(plane, length); }