diff options
Diffstat (limited to 'Build/source/utils/sam2p/in_lbm.cpp')
-rw-r--r-- | Build/source/utils/sam2p/in_lbm.cpp | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/Build/source/utils/sam2p/in_lbm.cpp b/Build/source/utils/sam2p/in_lbm.cpp new file mode 100644 index 00000000000..e633ff70341 --- /dev/null +++ b/Build/source/utils/sam2p/in_lbm.cpp @@ -0,0 +1,277 @@ +/* + * 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__ +#pragma implementation +#endif + +#include "image.hpp" +#include "error.hpp" + +#if USE_IN_LBM + +#include <string.h> /* 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 *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<wd;i++) { + mask=1; depth2=depth; take=(unsigned char*)lines; res=0; while (depth2--!=0) { + if (0!=(*take&bit)) res|=mask; + mask<<=1; + take+=byteswide; + } + *picput++=res; + if (bit==1) { bit=128; ++lines; } else bit>>=1; + } +} +#endif + +void LBMRead::errUnEOF() { + Error::sev(Error::EERROR) << "LBM: unexpected EOF" << (Error*)0; +} +void LBMRead::err(char *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;i<sizeof(temparea);i++) temparea[i]=getcn(); + // for (;i<size;i++) getcn(); + // } else for (i=0;i<size;i++) temparea[i]=getcn(); + if (size<20) errUnEOF(); + lbm_wd=getu16(); + lbm_ht=getu16(); + if (getu32()!=0) err("LBM: expected offsets==0"); + depth=getcn(); + if (depth!=24 && (depth<1 || depth>8)) 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<<depth, 8); + memset(img->getHeadp(), '\0', 3*(1<<depth)); /* clear palette */ + } + } else if (type==BODY) { + if (!had_cmap) err("LBM: should be CMAP, BODY"); + // fprintf(stderr, "wd=%u, %u exp=%u\n", lbm_wd, size, byteswide*depth*lbm_ht); + if (comp==0 && size!=byteswide*depth*lbm_ht) err("LBM: wrong BODY length"); + char *buf=new char[byteswide*depth], *picput=img->getRowbeg(); // const_cast<char*>(img->getCString()); + for (i=0;i<lbm_ht;i++) { + // fprintf(stderr, "i=%u ht=%u\n", i, lbm_ht); + if (comp) { for (j=0;j<depth;j++) size-=getUnpack(byteswide, buf+byteswide*j); } + else { for (j=0;j<depth*byteswide;j++) buf[j]=getcn(); } + /* ^^^ Imp: test !comp: find uncompressed LBM files */ + if ((s32_t)size<0) goto dtl; + + /* debit() */ + /* LBM compression is quite stupid: it run-length-compresses + * individiual bits of the color depth as 8-bit bytes. Plus it requires + * each bit vector to be aligned to 16-bit boundary. + */ + Image::Sampled::dimen_t depth2, bit=128, res, i, mask; + // unsigned byteswide=((lbm_wd+15)>>4)<<1; + unsigned char *take, *lines=(unsigned char*)buf; + if (depth!=24) { + for (i=0;i<lbm_wd;i++) { + mask=1; depth2=depth; take=lines; res=0; while (depth2--!=0) { + if (0!=(*take&bit)) res|=mask; + mask<<=1; + take+=byteswide; + } + if (res==transp) had_transp=true; + *picput++=res; + if (bit==1) { bit=128; ++lines; } else bit>>=1; + } + } else { + u32_t res; + for (i=0;i<lbm_wd;i++) { + mask=1; depth2=24; take=lines; res=0; while (depth2--!=0) { + if (0!=(*take&bit)) res|=mask; + mask<<=1; + take+=byteswide; + } + /* No transparency here. */ + *picput++=res; /* Shift order verified. */ + *picput++=res>>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<Image::Indexed*>(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<<depth)) err("LBM: CMAP too large"); + char *colormap=img->getHeadp(); + // fprintf(stderr,"Si=%d size=%u\n", img->getRowbeg()-colormap, size); + for (i=0;i<size;i++) colormap[i]=getcn(); + had_cmap=true; + } else { + Error::sev(Error::WARNING) << "LBM: unknown tag ignored: " << type << (Error*)0; + while (size--) MACRO_GETC(f); + } + if (do_skip) getcn(); + // fprintf(stderr,"do_skip=%d t=%lu\n", do_skip, ftell(f)); + } + if (!had_body) err("LBM: missing BODY"); + return img; +} + +static Image::Sampled *in_lbm_reader(Image::Loader::UFD *ufd, SimBuffer::Flat const&) { + return LBMRead(((Filter::UngetFILED*)ufd)->getFILE(/*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 }; |