#include #include #include #include #include #include #include #include #include #include #include #include "jiff.h" /* Code from in this file modified from WBLander Fred Fish #114 */ /* Orginal authors Peter da Silva and Karl Lehenbauer */ /* #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 struct Library *GfxBase, *IntuitionBase,*OpenLibrary(); static struct ILBM_info *read_ilbm(), *read_body(); static struct ILBM_info *root_info; void free_image(); #define CHIP (MEMF_PUBLIC|MEMF_CHIP) struct Screen *show_iff(); struct ILBM_info *load_iff(); extern struct Screen *OpenScreen(); struct NewScreen ShowNewScreen; struct TextAttr Tfont = { "topaz.font", 8, 0, 0}; void put_ea_cmap(screen, cmap, colors) struct Screen *screen; unsigned char *cmap; int colors; { int i; for (i=0; iViewPort, i, (long)cmap[3*i+0]>>4, (long)cmap[3*i+1]>>4, (long)cmap[3*i+2]>>4); } struct Screen *show_iff(info) struct ILBM_info *info; { struct Screen *screen; ShowNewScreen.LeftEdge = 0; ShowNewScreen.TopEdge = 0; ShowNewScreen.Width = info->header.w; ShowNewScreen.Height = info->header.h; ShowNewScreen.Depth = info->header.nPlanes; ShowNewScreen.DetailPen = 0; ShowNewScreen.BlockPen = 1; if((info->viewmode & HAM) != HAM && (info->viewmode & DUALPF) != DUALPF && info->header.nPlanes > 5 ) { info->viewmode |= HAM; } ShowNewScreen.ViewModes = info->viewmode; ShowNewScreen.Type = CUSTOMSCREEN | CUSTOMBITMAP | SCREENBEHIND; ShowNewScreen.Font = &Tfont; ShowNewScreen.DefaultTitle = "Fish Tank"; ShowNewScreen.Gadgets = NULL; ShowNewScreen.CustomBitMap = &info->bitmap; if ( (screen = OpenScreen(&ShowNewScreen) ) != NULL) put_ea_cmap(screen, info->cmap, info->colors); ScreenToFront(screen); return screen; } struct ILBM_info *load_iff(file) char *file; { return read_iff(file, 0); } struct Screen *picture(mode,fname) int mode; char *fname; { static struct ILBM_info *iff_info; static struct Screen *iff_screen; if(!mode) /* For mode=0 show picture */ { iff_info=load_iff(fname); iff_screen=show_iff(iff_info); return(iff_screen); } if(iff_screen!=NULL) { CloseScreen(iff_screen); free_image(iff_info); return(NULL); } return(NULL); } /* ********************************************************************* */ /* */ /* 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 ] */ /* ********************************************************************* */ #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); }