/* * in_lbm.cpp -- read a Deluxe Paint IFF/ILBM file * by pts@fazekas.hu at Fri Mar 1 17:12:16 CET 2002 * -- Fri Mar 1 22:28:03 CET 2002 * * I've ripped the reader code from xscavenger's source, and enhanced it * a little bit (at Fri Mar 1 17:12:43 CET 2002), but I still think that * this can read only the minority of the LBM files around. */ /* Imp: get docs about the LBM format, and rewrite this from scratch */ #ifdef __GNUC__ #ifndef __clang__ #pragma implementation #endif #endif #include "image.hpp" #include "error.hpp" #if USE_IN_LBM #include /* memchr() */ #include "gensio.hpp" #define FORM 0x464f524dL #define ILBM 0x494c424dL #define PBM 0x50424d20L #define CMAP 0x434d4150L #define BODY 0x424f4459L #define BMHD 0x424d4844L /* typedef unsigned char uchar; */ #define MAXBYTES 128 /* ?? */ /* --- */ #if SIZEOF_INT>=4 typedef unsigned int u32_t; typedef signed int s32_t; #else typedef unsigned long u32_t; typedef signed long s32_t; #endif class LBMRead { public: inline LBMRead(FILE *f_): f(f_) {} /* inline ~LBMRead() { fclose(f); } */ Image::Sampled *doit(); protected: inline int getcn(); void errUnEOF(); void err(char const*s); u32_t getUnpack(unsigned len, char *where); u32_t getu32(); unsigned getu16(); FILE *f; }; //static inline int fixbyte(char *take,int bit,int depth) { // int res=0,mask=1; // while (depth--) { // if (*take & bit) res|=mask; // mask<<=1; // take+=MAXBYTES; // } // return res; //} #if 0 static void debit(char *picput, char *lines, unsigned wd, unsigned depth) { unsigned depth2, bit=128, res, i, mask; unsigned byteswide=((wd+15)>>4)<<1; unsigned char *take; for (i=0;i>=1; } } #endif void LBMRead::errUnEOF() { Error::sev(Error::EERROR) << "LBM: unexpected EOF" << (Error*)0; } void LBMRead::err(char const*s) { Error::sev(Error::EERROR) << s << (Error*)0; } inline int LBMRead::getcn() { int i=MACRO_GETC(f); if (i==-1) errUnEOF(); return i; } u32_t LBMRead::getUnpack(unsigned len, char *where) { /* RLE decompression */ int ch,ch2; u32_t sofar=0; while (len>0) { ch=getcn(); if (ch<128) { ch++; assert(ch>=1); if (len<(unsigned)ch) err("LBM: packet#1 too long"); len-=ch; sofar+=1+ch; while (ch--) *where++=getcn(); } else { ch=1-(ch-256); /* 2..129 */ assert(ch>=1); // fprintf(stderr, "len=%u ch=%u\n", len, ch); if (len<(unsigned)ch) err("LBM: packet#2 too long"); len-=ch; // fprintf(stderr, "xlen=%u ch=%u\n", len, ch); ch2=getcn(); sofar+=2; while (ch--) *where++=ch2; } } return sofar; } u32_t LBMRead::getu32() { u32_t val1=0; val1=getcn()<<24L; val1|=getcn()<<16L; val1|=getcn()<<8; val1|=getcn(); return val1; } unsigned LBMRead::getu16() { u32_t val1=0; val1|=getcn()<<8; val1|=getcn(); return val1; } Image::Sampled *LBMRead::doit() { char temparea[16]; u32_t type, size, i; unsigned char comp=0; unsigned j; int ii; Image::Sampled::dimen_t lbm_wd, lbm_ht, byteswide, depth=0; /* pts */ unsigned transp=256; Image::Sampled *img=(Image::Sampled*)NULLP; bool had_cmap=false, had_body=false, do_skip, had_transp=false; /* sprintf(temparea,"%s/%s/%s",localname,localdirname,name); */ for (i=0;i<12;i++) temparea[i]=getcn(); if (0!=memcmp(temparea,"FORM",4) || 0!=memcmp(temparea+8,"ILBM",4)) err("LBM: magic says: this is not an LBM"); lbm_wd=lbm_ht=byteswide=0; while ((ii=MACRO_GETC(f))!=-1 && ii!='\0') { ungetc(ii,f); if ((type=getu32())==0xffffffffL) break; size=getu32(); do_skip=(size&1); /* pad to even size */ // fprintf(stderr,"size=%u\n", size); if (type==BMHD) { if (img!=NULLP) err("LBM: duplicate BMHD"); // if (size>sizeof(temparea)) { // for (i=0;i8)) err("LBM: invalid color depth"); if (getcn()!=0) err("LBM: expected masking==0"); if ((comp=getcn())>=2) err("LBM: expected comp==0 || comp==1"); getcn(); /* ignore padding */ transp=getu16(); /* index of transparent color */ // fprintf(stderr, "htt=%u transp=%u\n", lbm_ht, transp); getu16(); /* Ignore aspect ratio. */ if (lbm_wd!=getu16() || lbm_ht!=getu16()) err("LBM: inconsistent dimens"); /* ^^^ Dat: pagex, pagey */ byteswide=((lbm_wd+15)>>4)<<1; /*printf("(%d,%d) %d bpp\n",lbm_wd,lbm_ht,depth);*/ if (depth==24) { had_cmap=true; img=new Image::RGB(lbm_wd, lbm_ht, 8); } else { img=new Image::Indexed(lbm_wd, lbm_ht, 1<getHeadp(), '\0', 3*(1<getRowbeg(); // const_cast(img->getCString()); for (i=0;i>4)<<1; unsigned char *take, *lines=(unsigned char*)buf; if (depth!=24) { for (i=0;i>=1; } } else { u32_t res; for (i=0;i>8; *picput++=res>>16; if (bit==1) { bit=128; ++lines; } else bit>>=1; } } } // fprintf(stderr,"size=%u\n", size); if (size>1) { dtl: err("LBM: data too long"); } if (size==1) getcn(); if (had_transp) { assert(depth!=24); static_cast(img)->setTransp(transp); } // img->getRowbeg()[0]='\001'; img->getRowbeg()[1]='\002'; delete [] buf; had_body=true; } else if (type==CMAP) { if (img==NULLP) err("LBM: should be: BMHD, CMAP"); if (had_cmap) err("LBM: duplicate CMAP"); if (size>3*(1U<getHeadp(); // fprintf(stderr,"Si=%d size=%u\n", img->getRowbeg()-colormap, size); for (i=0;igetFILE(/*seekable:*/false)).doit(); /* ^^^ Destructor: fclose((FILE*)file_); */ } static Image::Loader::reader_t in_lbm_checker(char buf[Image::Loader::MAGIC_LEN], char [Image::Loader::MAGIC_LEN], SimBuffer::Flat const&, Image::Loader::UFD*) { return (0==memcmp(buf,"FORM",4) && 0==memcmp(buf+8,"ILBM",4)) ? in_lbm_reader : 0; } #else #define in_lbm_checker NULLP #endif /* USE_IN_XPM */ Image::Loader in_lbm_loader = { "LBM", in_lbm_checker, 0 };