#include <clib/alib_protos.h>
#include <clib/datatypes_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/iffparse_protos.h>
#include <clib/intuition_protos.h>
#include <clib/render_protos.h>
#include <clib/utility_protos.h>
#include <clib/xpkmaster_protos.h>
#include <render/renderhooks.h>
#include <cybergraphx/cybergraphics.h>
#include <datatypes/pictureclass.h>
#include <exec/memory.h>
#include <intuition/icclass.h>
//#include <libraries/rgfx.h>
#include <string.h>
#include "class.h"
#include "rgfx.h"

struct Arg1
{
long *mode,*dither,*depth;
char *xpk;
long *xpkmode;
char *password;
};

ULONG SaveRGFX(IClass *cl,Object *obj,dtWrite *msg);

extern Library *SuperClassBase;

static long iff2dos[]=
{
0,
0,
DTERROR_INVALID_DATA,
ERROR_NO_FREE_STORE,
ERROR_SEEK_ERROR,
ERROR_SEEK_ERROR,
ERROR_SEEK_ERROR,
DTERROR_INVALID_DATA,
DTERROR_INVALID_DATA,
ERROR_OBJECT_WRONG_TYPE,
ERROR_REQUIRED_ARG_MISSING,
0xDEADDEAD
};

static long chunks[]=
{
ID_RGFX,ID_RGHD,
ID_RGFX,ID_RSCM,
ID_RGFX,ID_RCOL,
ID_RGFX,ID_NAME,
ID_RGFX,ID_AUTH,
ID_RGFX,ID_ANNO,
ID_RGFX,ID_Copyright,
ID_RGFX,ID_FVER
};

void ReadPrefs(Data *data)
{
char *var;
data->mode=1;
data->dither=0;
data->depth=8;
strcpy(data->xpk,"NUKE");
data->xpkmode=100;
if(data->password)
	{
	FreeVec(data->password);
	data->password=0;
	}
if(var=(char *)AllocVec(256,0))
	{
	if(GetVar("ENV:DataTypes/rgfx.prefs",var,256,LV_VAR|GVF_GLOBAL_ONLY)>=0)
		{
		RDArgs *rdargs;
      if(rdargs=(RDArgs *)AllocDosObject(DOS_RDARGS,0))
			{
			RDArgs *args;
			Arg1 para;
			rdargs->RDA_Source.CS_Buffer=var;
			rdargs->RDA_Source.CS_Length=strlen(var);
			rdargs->RDA_Source.CS_CurChr=0;
			memset(&para,0,sizeof(Arg1));
			if(args=ReadArgs("MODE/A/N,DITHER/A/N,DEPTH/A/N,XPK/A,XPKMODE/A/N,PASSWORD",(long *)&para,rdargs))
				{
				data->mode=*para.mode;
				if(data->mode<0) data->mode=0;
				else if(data->mode>1) data->mode=1;
				data->dither=*para.dither;
				if(data->dither<0) data->dither=0;
				else if(data->dither>1) data->dither=1;
				data->depth=*para.depth;
				if(data->depth<3) data->depth=3;
				else if(data->depth>8) data->depth=8;
				strncpy(data->xpk,para.xpk,4);
				data->xpk[4]=0;
				data->xpkmode=*para.xpkmode;
				if(data->xpkmode<0) data->xpkmode=0;
				else if(data->xpkmode>100) data->xpkmode=100;
				if(para.password)
					{
					if(data->password=(char *)AllocVec(strlen(para.password)+1,MEMF_CLEAR)) strcpy(data->password,para.password);
					}
				FreeArgs(args);
				}
			FreeDosObject(DOS_RDARGS,rdargs);
			}
		}
	FreeVec(var);
	}
if(SuperClassBase->lib_Version!=43) data->mode=0;
}

ULONG Colors2DT(Object *obj,UBYTE *color)
{
UBYTE *cr;
ULONG *cregs,i,num,error=0;
GetDTAttrs(obj,PDTA_NumColors,&num,PDTA_ColorRegisters,&cr,PDTA_CRegs,&cregs,TAG_END);
if(cr&&cregs)
	{
	for(i=0;i<num;i++,cr+=3,cregs+=3,color+=4)
		{
		cr[0]=color[1];
		cr[1]=color[2];
		cr[2]=color[3];
		cregs[0]=cr[0]<<24;
		cregs[1]=cr[1]<<24;
		cregs[2]=cr[2]<<24;
		}
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

static void GetRGHD(Object *obj,RGHD *rh,BitMapHeader *bh,Data *data)
{
bh->bmh_Left=rh->rgfx_LeftEdge;
bh->bmh_Top=rh->rgfx_TopEdge;
bh->bmh_Width=rh->rgfx_Width;
bh->bmh_Height=rh->rgfx_Height;
bh->bmh_PageWidth=rh->rgfx_PageWidth?rh->rgfx_PageWidth:bh->bmh_Width;
bh->bmh_PageHeight=rh->rgfx_PageHeight?rh->rgfx_PageHeight:bh->bmh_Height;
bh->bmh_Depth=(data->mode||rh->rgfx_Depth<=8)?rh->rgfx_Depth:data->depth;
bh->bmh_Compression=cmpByteRun1;
bh->bmh_XAspect=rh->rgfx_XAspect;
bh->bmh_YAspect=rh->rgfx_YAspect;
SetDTAttrs(obj,0,0,DTA_NominalHoriz,bh->bmh_Width,DTA_NominalVert,bh->bmh_Height,TAG_END);
}

static ULONG GetRSCM(Object *obj,IFFHandle *iff,BitMapHeader *bh,Data *data,ULONG rgfxdepth)
{
ULONG mode=0,numc=0;
if(rgfxdepth<=8||data->mode)
	{
	StoredProperty *sp;
	mode=INVALID_ID;
	if(sp=FindProp(iff,ID_RGFX,ID_RSCM))
		{
		RSCM *rscm=(RSCM *)sp->sp_Data;
		if(!ModeNotAvailable(rscm->rscm_AGA))
			{
			ULONG dipf=0;
			if(rscm->rscm_AGA&HAM_KEY)
				{
				numc=(bh->bmh_Depth==8)?64:16;
				dipf=DIPF_IS_HAM;
				}
			else if(rscm->rscm_AGA&EXTRAHALFBRITE_KEY)
				{
				numc=32;
				dipf=DIPF_IS_EXTRAHALFBRITE;
				}
			if(dipf) mode=BestModeID(
			BIDTAG_NominalWidth,bh->bmh_PageWidth,BIDTAG_NominalHeight,bh->bmh_PageHeight,
			BIDTAG_DesiredWidth,bh->bmh_Width,BIDTAG_DesiredHeight,bh->bmh_Height,BIDTAG_Depth,bh->bmh_Depth,
			BIDTAG_DIPFMustHave,dipf,BIDTAG_DIPFMustNotHave,DIPF_IS_DUALPF|DIPF_IS_PF2PRI,TAG_END);
			}
		}
	if(mode==INVALID_ID)
		{
		mode=BestModeID(
		BIDTAG_NominalWidth,bh->bmh_PageWidth,BIDTAG_NominalHeight,bh->bmh_PageHeight,
		BIDTAG_DesiredWidth,bh->bmh_Width,BIDTAG_DesiredHeight,bh->bmh_Height,
		BIDTAG_Depth,bh->bmh_Depth,
		BIDTAG_DIPFMustNotHave,DIPF_IS_DUALPF|DIPF_IS_PF2PRI|DIPF_IS_HAM|DIPF_IS_EXTRAHALFBRITE,TAG_END);
		numc=1<<bh->bmh_Depth;
		}
	if(mode!=INVALID_ID)
		{
		SetDTAttrs(obj,0,0,PDTA_ModeID,mode,TAG_END);
		if(numc) SetDTAttrs(obj,0,0,PDTA_NumColors,numc,TAG_END);
		}
	}
else
	{
	if(!data->mode)
		{
		mode=BestModeID(
		BIDTAG_NominalWidth,bh->bmh_PageWidth,BIDTAG_NominalHeight,bh->bmh_PageHeight,
		BIDTAG_DesiredWidth,bh->bmh_Width,BIDTAG_DesiredHeight,bh->bmh_Height,
		BIDTAG_Depth,bh->bmh_Depth,
		BIDTAG_DIPFMustNotHave,DIPF_IS_DUALPF|DIPF_IS_PF2PRI|DIPF_IS_HAM|DIPF_IS_EXTRAHALFBRITE,TAG_END);
		numc=1<<bh->bmh_Depth;
		SetDTAttrs(obj,0,0,PDTA_ModeID,mode,PDTA_NumColors,numc,TAG_END);
		}
	}
return mode;
}

static ULONG GetRCOL(Object *obj,IFFHandle *iff,RGHD *rh)
{
ULONG error=0;
if(rh->rgfx_Depth<=8)
	{
	StoredProperty *sp;
	if(sp=FindProp(iff,ID_RGFX,ID_RCOL))
		{
		RCOL *rcol=(RCOL *)sp->sp_Data;
		ULONG n,*cregs;
		UBYTE *cr,*p;
		GetDTAttrs(obj,PDTA_NumColors,&n,PDTA_ColorRegisters,&cr,PDTA_CRegs,&cregs,TAG_END);
		if(cr&&cregs)
			{
			ULONG i;
			n*=3;
			for(i=0,p=rcol->rcol_Colors[0];i<n;i++,p++,cr++,cregs++)
				{
				*cr=*p;
				*cregs=(*p)<<24;
				}
			}
		else error=ERROR_NO_FREE_STORE;
		}
	else error=ERROR_REQUIRED_ARG_MISSING;
	}
return error;
}

static ULONG GetBody_BP8(IFFHandle *iff,RGHD *rh,BitMap *bm,Data *data)
{
ULONG error=0;
ULONG d;
for(d=0;d<rh->rgfx_Depth;d++)
	{
	ULONG y;
	UBYTE *pl=bm->Planes[d];
	for(y=0;y<rh->rgfx_Height;y++,pl+=bm->BytesPerRow)
		{
		long err;
		if((err=ReadChunkBytes(iff,pl,rh->rgfx_BytesPerLine)<0))
			{
			error=iff2dos[-err];
			break;
			}
		}
	}
return error;
}

static ULONG GetBody_BC8(IFFHandle *iff,RGHD *rh,BitMap *bm,Data *data)
{
ULONG error=0;
BitMap *tbm;
if(tbm=AllocBitMap(rh->rgfx_Width,1,rh->rgfx_Depth,0,bm))
	{
	UBYTE *pix;
	if(pix=(UBYTE *)AllocVec(((rh->rgfx_Width+16)>>4)<<4,0))
		{
		ULONG y;
		RastPort rp,trp;
		InitRastPort(&rp);
		InitRastPort(&trp);
		rp.BitMap=bm;
		trp.BitMap=tbm;
		for(y=0;y<rh->rgfx_Height;y++)
			{
			long err;
			if((err=ReadChunkBytes(iff,pix,rh->rgfx_Width))<0)
				{
				error=iff2dos[-err];
				break;
				}
			WritePixelLine8(&rp,0,y,rh->rgfx_Width,pix,&trp);
			}
		FreeVec(pix);
		}
	else error=ERROR_NO_FREE_STORE;
	FreeBitMap(tbm);
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

static ULONG GetBody_RGB_V43(Object *obj,IFFHandle *iff,RGHD *rh,Data *data)
{
ULONG error=0;
UBYTE *pix;
long err;
if(pix=(UBYTE *)AllocVec(rh->rgfx_BytesPerLine*rh->rgfx_Height,0))
	{
	if((err=ReadChunkBytes(iff,pix,rh->rgfx_BytesPerLine*rh->rgfx_Height))<0) error=iff2dos[-err];
	else DoMethod(obj,PDTM_WRITEPIXELARRAY,pix,RECTFMT_RGB,rh->rgfx_BytesPerLine,0,0,rh->rgfx_Width,rh->rgfx_Height);
	FreeVec(pix);
	}
else if(pix=(UBYTE *)AllocVec(rh->rgfx_BytesPerLine,0))
	{
	ULONG y;
	for(y=0;y<rh->rgfx_Height;y++)
		{
		if((err=ReadChunkBytes(iff,pix,rh->rgfx_BytesPerLine))<0)
			{
			error=iff2dos[-err];
			break;
			}
		DoMethod(obj,PDTM_WRITEPIXELARRAY,pix,RECTFMT_RGB,rh->rgfx_BytesPerLine,0,y,rh->rgfx_Width,1);
		}
	FreeVec(pix);
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

static ULONG GetBody_RGB(Object *obj,IFFHandle *iff,RGHD *rh,BitMapHeader *bh,BitMap *bm,Data *data)
{
ULONG error=0;
UBYTE *rgb;
if(rgb=(UBYTE *)AllocVec(rh->rgfx_Width*rh->rgfx_Height*4,MEMF_CLEAR))
	{
	UBYTE *buffer;
	if(buffer=(UBYTE *)AllocVec(rh->rgfx_BytesPerLine,0))
		{
		ULONG y;
		UBYTE *p1=rgb;
		for(y=0;y<rh->rgfx_Height;y++)
			{
			ULONG x;
			long err;
			UBYTE *p2=buffer;
			if((err=ReadChunkBytes(iff,buffer,rh->rgfx_BytesPerLine))<0)
				{
				error=iff2dos[-err];
				break;
				}
			for(x=0;x<rh->rgfx_Width;x++,p1+=4,p2+=3)
				{
				p1[1]=p2[0];
				p1[2]=p2[1];
				p1[3]=p2[2];
				}
			}
		FreeVec(buffer);
		if(!error)
			{
			APTR rmh;
			if(rmh=CreateRMHandler(RND_MemType,RMHTYPE_POOL,TAG_END))
				{
				ULONG *palette;
				if(palette=CreatePalette(RND_RMHandler,rmh,TAG_END))
					{
					APTR hst;
					if(hst=CreateHistogram(RND_RMHandler,rmh,TAG_END))
						{
						if(AddRGBImage(hst,(ULONG *)rgb,rh->rgfx_Width,rh->rgfx_Height,TAG_END)==ADDH_SUCCESS)
							{
							ULONG numc;
							GetDTAttrs(obj,PDTA_NumColors,&numc,TAG_END);
							if(ExtractPalette(hst,palette,numc,RND_ColorMode,COLORMODE_CLUT,TAG_END)==EXTP_SUCCESS)
								{
								UBYTE *chunky;
								if(chunky=(UBYTE *)AllocVec(rh->rgfx_Width*rh->rgfx_Height,0))
									{
									if(Render((ULONG *)rgb,rh->rgfx_Width,rh->rgfx_Height,chunky,palette,RND_DitherMode,data->dither,RND_ColorMode,COLORMODE_CLUT,TAG_END)==REND_SUCCESS)
										{
										UBYTE *color;
										if(color=(UBYTE *)AllocVec((1<<bh->bmh_Depth)*4,0))
											{
											ExportPalette(palette,color,TAG_END);
											if(!(error=Colors2DT(obj,color))) Chunky2BitMap(chunky,0,0,rh->rgfx_Width,rh->rgfx_Height,bm,0,0,TAG_END);
											FreeVec(color);
											}
										else error=ERROR_NO_FREE_STORE;
										}
									else error=ERROR_NO_FREE_STORE;
									FreeVec(chunky);
									}
								else error=ERROR_NO_FREE_STORE;
								}
							else error=ERROR_NO_FREE_STORE;
							}
						else error=ERROR_NO_FREE_STORE;
						DeleteHistogram(hst);
						}
					else error=ERROR_NO_FREE_STORE;
					DeletePalette(palette);
					}
				else error=ERROR_NO_FREE_STORE;
				DeleteRMHandler(rmh);
				}
			else error=ERROR_NO_FREE_STORE;
			}
		}
	else error=ERROR_NO_FREE_STORE;
	FreeVec(rgb);
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

static ULONG GetBody_XPKBP8(IFFHandle *iff,RGHD *rh,BitMap *bm,Data *data)
{
ULONG error=0,d,y;
XpkFib *fib;
UBYTE *mem,*pl;
if(!XpkUnpackTags(XPK_InFH,iff->iff_Stream,XPK_GetOutBuf,&mem,XPK_GetOutBufLen,&y,TAG_END))
	{
	UBYTE *p=mem;
	for(d=0;d<rh->rgfx_Depth;d++)
		{
		pl=bm->Planes[d];
		for(y=0;y<rh->rgfx_Height;y++,pl+=bm->BytesPerRow,p+=rh->rgfx_BytesPerLine) CopyMem(p,pl,bm->BytesPerRow);
		}
	FreeMem(mem,y);
	}
else if(!XpkOpenTags(&fib,XPK_InFH,iff->iff_Stream,TAG_END))
	{
	if(mem=(UBYTE *)AllocVec(fib->xf_NLen,0))
		{
		long p=-1,clen=-1;
		for(d=0;d<rh->rgfx_Depth;d++)
			{
			pl=bm->Planes[d];
			for(y=0;y<rh->rgfx_Height;y++,pl+=bm->BytesPerRow)
				{
				ULONG x;
				for(x=0;x<rh->rgfx_BytesPerLine;x++)
					{
					if(p>=clen)
						{
						if((clen=XpkRead(fib,mem,fib->xf_NLen))<0)
							{
							error=DTERROR_INVALID_DATA;
							y=rh->rgfx_Height;
							d=rh->rgfx_Depth;
							break;
							}
						p=0;
						}
					pl[x]=mem[p];
					p++;
					}
				}
			}
		FreeVec(mem);
		}
	else error=ERROR_NO_FREE_STORE;
	XpkClose(fib);
	}
else error=DTERROR_INVALID_DATA;
return error;
}

static ULONG GetBody_XPKBC8(IFFHandle *iff,RGHD *rh,BitMap *bm,Data *data)
{
ULONG error=0;
BitMap *tbm;
if(tbm=AllocBitMap(rh->rgfx_Width,1,rh->rgfx_Depth,0,bm))
	{
	ULONG y,pixlen;
	UBYTE *pix;
	XpkFib *fib;
	RastPort rp,trp;
	InitRastPort(&rp);
	InitRastPort(&trp);
	rp.BitMap=bm;
	trp.BitMap=tbm;
	if(!XpkUnpackTags(XPK_InFH,iff->iff_Stream,XPK_GetOutBuf,&pix,XPK_GetOutBufLen,&pixlen,TAG_END))
		{
		UBYTE *p=pix;
		for(y=0;y<rh->rgfx_Height;y++,p+=rh->rgfx_Width) WritePixelLine8(&rp,0,y,rh->rgfx_Width,p,&trp);
		FreeMem(pix,pixlen);
		}
	else if(!XpkOpenTags(&fib,XPK_InFH,iff->iff_Stream,TAG_END))
		{
		UBYTE *mem;
		if(mem=(UBYTE *)AllocVec(fib->xf_NLen,0))
			{
			if(pix=(UBYTE *)AllocVec(((rh->rgfx_Width+16)>>4)<<4,0))
				{
				long p=-1,clen=-1;
				for(y=0;y<rh->rgfx_Height;y++)
					{
					ULONG x;
					for(x=0;x<rh->rgfx_Width;x++)
						{
						if(p>=clen)
							{
							if((clen=XpkRead(fib,mem,fib->xf_NLen))<0)
								{
								error=DTERROR_INVALID_DATA;
								y=rh->rgfx_Height;
								break;
								}
							p=0;
							}
						pix[x]=mem[p];
						p++;
						}
					WritePixelLine8(&rp,0,y,rh->rgfx_Width,pix,&trp);
					}
				FreeVec(pix);
				}
			else error=ERROR_NO_FREE_STORE;
			FreeVec(mem);
			}
		else error=ERROR_NO_FREE_STORE;
		XpkClose(fib);
		}
	else error=DTERROR_INVALID_DATA;
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

static ULONG GetBody_XPKRGB_V43(Object *obj,IFFHandle *iff,RGHD *rh,Data *data)
{
ULONG error=0,pixlen;
XpkFib *fib;
UBYTE *pix;
if(!XpkUnpackTags(XPK_InFH,iff->iff_Stream,XPK_GetOutBuf,&pix,XPK_GetOutBufLen,&pixlen,TAG_END))
	{
	DoMethod(obj,PDTM_WRITEPIXELARRAY,pix,RECTFMT_RGB,rh->rgfx_BytesPerLine,0,0,rh->rgfx_Width,rh->rgfx_Height);
	FreeMem(pix,pixlen);
	}
else if(!XpkOpenTags(&fib,XPK_InFH,iff->iff_Stream,TAG_END))
	{
	UBYTE *mem;
	if(mem=(UBYTE *)AllocVec(fib->xf_NLen,0))
		{
		if(pix=(UBYTE *)AllocVec(rh->rgfx_BytesPerLine,0))
			{
			long p=-1,clen=-1;
			ULONG y;
			for(y=0;y<rh->rgfx_Height;y++)
				{
				ULONG x;
				for(x=0;x<rh->rgfx_BytesPerLine;x++)
					{
					if(p>=clen)
						{
						if((clen=XpkRead(fib,mem,fib->xf_NLen))<0)
							{
							error=DTERROR_INVALID_DATA;
							y=rh->rgfx_Height;
							break;
							}
						p=0;
						}
					pix[x]=mem[p];
					p++;
					}
				DoMethod(obj,PDTM_WRITEPIXELARRAY,pix,RECTFMT_RGB,rh->rgfx_BytesPerLine,0,y,rh->rgfx_Width,1);
				}
			FreeVec(pix);
			}
		else error=ERROR_NO_FREE_STORE;
		FreeVec(mem);
		}
	else error=ERROR_NO_FREE_STORE;
	XpkClose(fib);
	}
else error=DTERROR_INVALID_DATA;
return error;
}

static ULONG GetBody_XPKRGB(Object *obj,IFFHandle *iff,RGHD *rh,BitMapHeader *bh,BitMap *bm,Data *data)
{
ULONG error=0;
XpkFib *fib;
if(!XpkOpenTags(&fib,XPK_InFH,iff->iff_Stream,TAG_END))
	{
	UBYTE *mem;
	if(mem=(UBYTE *)AllocVec(fib->xf_NLen,0))
		{
		UBYTE *rgb;
		if(rgb=(UBYTE *)AllocVec(rh->rgfx_Width*rh->rgfx_Height*4,MEMF_CLEAR))
			{
			UBYTE *buffer;
			if(buffer=(UBYTE *)AllocVec(rh->rgfx_BytesPerLine,0))
				{
				long p=-1,clen=-1;
				ULONG y;
				UBYTE *p1=rgb;
				for(y=0;y<rh->rgfx_Height;y++)
					{
					ULONG x;
					UBYTE *p2=buffer;
					for(x=0;x<rh->rgfx_BytesPerLine;x++)
						{
						if(p>=clen)
							{
							if((clen=XpkRead(fib,mem,fib->xf_NLen))<0)
								{
								error=DTERROR_INVALID_DATA;
								y=rh->rgfx_Height;
								break;
								}
							p=0;
							}
						buffer[x]=mem[p];
						p++;
						}
					if(error) break;
					for(x=0;x<rh->rgfx_Width;x++,p1+=4,p2+=3)
						{
						p1[1]=p2[0];
						p1[2]=p2[1];
						p1[3]=p2[2];
						}
					}
				FreeVec(buffer);
				if(!error)
					{
					APTR rmh;
					if(rmh=CreateRMHandler(RND_MemType,RMHTYPE_POOL,TAG_END))
						{
						ULONG *palette;
						if(palette=CreatePalette(RND_RMHandler,rmh,TAG_END))
							{
							APTR hst;
							if(hst=CreateHistogram(RND_RMHandler,rmh,TAG_END))
								{
								if(AddRGBImage(hst,(ULONG *)rgb,rh->rgfx_Width,rh->rgfx_Height,TAG_END)==ADDH_SUCCESS)
									{
									ULONG numc;
									GetDTAttrs(obj,PDTA_NumColors,&numc,TAG_END);
									if(numc)
										{
										if(ExtractPalette(hst,palette,numc,RND_ColorMode,COLORMODE_CLUT,TAG_END)==EXTP_SUCCESS)
											{
											UBYTE *chunky;
											if(chunky=(UBYTE *)AllocVec(rh->rgfx_Width*rh->rgfx_Height,0))
												{
												if(Render((ULONG *)rgb,rh->rgfx_Width,rh->rgfx_Height,chunky,palette,RND_DitherMode,data->dither,RND_ColorMode,COLORMODE_CLUT,TAG_END)==REND_SUCCESS)
													{
													UBYTE *color;
													if(color=(UBYTE *)AllocVec((1<<bh->bmh_Depth)*4,0))
														{
														ExportPalette(palette,color,TAG_END);
														if(!(error=Colors2DT(obj,color))) Chunky2BitMap(chunky,0,0,rh->rgfx_Width,rh->rgfx_Height,bm,0,0,TAG_END);
														FreeVec(color);
														}
													else error=ERROR_NO_FREE_STORE;
													}
												else error=ERROR_NO_FREE_STORE;
												FreeVec(chunky);
												}
											else error=ERROR_NO_FREE_STORE;
											}
										else error=ERROR_NO_FREE_STORE;
										}
									else error=ERROR_NO_FREE_STORE;
									}
								else error=ERROR_NO_FREE_STORE;
								DeleteHistogram(hst);
								}
							else error=ERROR_NO_FREE_STORE;
							DeletePalette(palette);
							}
						else error=ERROR_NO_FREE_STORE;
						DeleteRMHandler(rmh);
						}
					else error=ERROR_NO_FREE_STORE;
					}
				}
			else error=ERROR_NO_FREE_STORE;
			FreeVec(rgb);
			}
		else error=ERROR_NO_FREE_STORE;
		FreeVec(mem);
		}
	else error=ERROR_NO_FREE_STORE;
	XpkClose(fib);
	}
else error=DTERROR_INVALID_DATA;
return error;
}

static ULONG GetPicture(IClass *cl,Object *obj)
{
ULONG error=0;
long err;
IFFHandle *iff;
BitMapHeader *bh;
GetDTAttrs(obj,DTA_Name,&bh,TAG_END);
if(bh) SetDTAttrs(obj,0,0,DTA_ObjName,bh,TAG_END);
GetDTAttrs(obj,DTA_Handle,&iff,PDTA_BitMapHeader,&bh,TAG_END);
if(bh)
	{
	if(!iff)
		{
		GetDTAttrs(obj,DTA_SourceType,&err,TAG_END);
		if(err!=DTST_RAM) return ERROR_REQUIRED_ARG_MISSING;
		else return 0;
		}
	if((err=PropChunks(iff,chunks,sizeof(chunks)/(2*sizeof(long))))<0) return iff2dos[-err];
	if((err=StopOnExit(iff,ID_RGFX,ID_RBOD))<0) return iff2dos[-err];
	for(;;)
		{
		StoredProperty *sp;
		if((err=ParseIFF(iff,IFFPARSE_SCAN))!=IFFERR_EOC)
			{
			error=iff2dos[-err];
			break;
			}
		if(sp=FindProp(iff,ID_RGFX,ID_NAME)) SetDTAttrs(obj,0,0,DTA_ObjName,sp->sp_Data,TAG_END);
		if(sp=FindProp(iff,ID_RGFX,ID_AUTH)) SetDTAttrs(obj,0,0,DTA_ObjAuthor,sp->sp_Data,TAG_END);
		if(sp=FindProp(iff,ID_RGFX,ID_ANNO)) SetDTAttrs(obj,0,0,DTA_ObjAnnotation,sp->sp_Data,TAG_END);
		if(sp=FindProp(iff,ID_RGFX,ID_Copyright)) SetDTAttrs(obj,0,0,DTA_ObjCopyright,sp->sp_Data,TAG_END);
		if(sp=FindProp(iff,ID_RGFX,ID_FVER)) SetDTAttrs(obj,0,0,DTA_ObjVersion,sp->sp_Data,TAG_END);
		if(sp=FindProp(iff,ID_RGFX,ID_RGHD))
			{
			RGHD *rh=(RGHD *)sp->sp_Data;
			Data *data=(Data *)INST_DATA(cl,obj);
			ContextNode *cn;
			ReadPrefs(data);
			GetRGHD(obj,rh,bh,data);
			if(GetRSCM(obj,iff,bh,data,rh->rgfx_Depth)==INVALID_ID) break;
			if(error=GetRCOL(obj,iff,rh)) break;
			if((cn=CurrentChunk(iff))&&(cn->cn_ID=='RBOD'))
				{
				BitMap *bm;
				switch(rh->rgfx_BitMapType)
					{
					case RMBT_BYTEPLANAR8:
						if(bm=AllocBitMap(rh->rgfx_Width,rh->rgfx_Height,rh->rgfx_Depth,BMF_CLEAR|BMF_DISPLAYABLE|BMF_STANDARD,0)) SetDTAttrs(obj,0,0,PDTA_BitMap,bm,TAG_END);
						else error=ERROR_NO_FREE_STORE;
						break;
					case RMBT_BYTECHUNKY8:
						if(bm=AllocBitMap(rh->rgfx_Width,rh->rgfx_Height,rh->rgfx_Depth,BMF_CLEAR|BMF_DISPLAYABLE,0)) SetDTAttrs(obj,0,0,PDTA_BitMap,bm,TAG_END);
						else error=ERROR_NO_FREE_STORE;
						break;
					case RMBT_3BYTERGB24:
						if(data->mode)
							{
							SetDTAttrs(obj,0,0,PDTA_SourceMode,PMODE_V43,PDTA_ModeID,0,TAG_END);
							GetDTAttrs(obj,PDTA_BitMap,&bm,TAG_END);
							if(!bm) error=ERROR_NO_FREE_STORE;
							}
						else
							{
							if(bm=AllocBitMap(rh->rgfx_Width,rh->rgfx_Height,data->depth,BMF_CLEAR|BMF_DISPLAYABLE|BMF_STANDARD,0)) SetDTAttrs(obj,0,0,PDTA_BitMap,bm,TAG_END);
							else error=ERROR_NO_FREE_STORE;
							}
						break;
					default:
						error=ERROR_NOT_IMPLEMENTED;
					}
				if(!error)
					{
					switch(rh->rgfx_Compression)
						{
						case RCMT_NOCOMPRESSION:
							switch(rh->rgfx_BitMapType)
								{
								case RMBT_BYTEPLANAR8:
									error=GetBody_BP8(iff,rh,bm,data);
									break;
								case RMBT_BYTECHUNKY8:
									error=GetBody_BC8(iff,rh,bm,data);
									break;
								case RMBT_3BYTERGB24:
									if(data->mode) error=GetBody_RGB_V43(obj,iff,rh,data);
									else error=GetBody_RGB(obj,iff,rh,bh,bm,data);
								}
							break;
						case RCMT_XPK:
							switch(rh->rgfx_BitMapType)
								{
								case RMBT_BYTEPLANAR8:
									error=GetBody_XPKBP8(iff,rh,bm,data);
									break;
								case RMBT_BYTECHUNKY8:
									error=GetBody_XPKBC8(iff,rh,bm,data);
									break;
								case RMBT_3BYTERGB24:
									if(data->mode) error=GetBody_XPKRGB_V43(obj,iff,rh,data);
									else error=GetBody_XPKRGB(obj,iff,rh,bh,bm,data);
								}
						}
					}
				break;
				}
			else error=DTERROR_INVALID_DATA;
			}
		else error=DTERROR_INVALID_DATA;
		}
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

static ULONG mNew(IClass *cl,Object *obj,opSet *msg)
{
TagItem *ti;
if(ti=FindTagItem(DTA_SourceType,(((opSet *)msg)->ops_AttrList)))
	{
	if(ti->ti_Data!=DTST_FILE&&ti->ti_Data!=DTST_CLIPBOARD&&ti->ti_Data!=DTST_RAM)
		{
		SetIoErr(ERROR_OBJECT_WRONG_TYPE);
		return 0;
		}
	}
if(obj==(Object *)cl)
	{
	if(obj=(Object *)DoSuperMethodA(cl,obj,Msg(msg)))
		{
		ULONG error;
		if(error=GetPicture(cl,obj))
			{
			SetIoErr(error);
			CoerceMethod(cl,obj,OM_DISPOSE);
			obj=0;
			}
		}
	}
else
	{
	SetIoErr(ERROR_NOT_IMPLEMENTED);
	obj=0;
	}
return ULONG(obj);
}

static ULONG mDispose(IClass *cl,Object *obj,Msg msg)
{
Data *data=(Data *)INST_DATA(cl,obj);
if(data->password) FreeVec(data->password);
return DoSuperMethodA(cl,obj,msg);
}

static ULONG mSet(IClass *cl,Object *obj,opSet *msg)
{
ULONG retval;
if(retval=DoSuperMethodA(cl,obj,Msg(msg)))
	{
	RastPort *rp;
	if(rp=ObtainGIRPort(msg->ops_GInfo))
		{
		DoMethod(obj,GM_RENDER,msg->ops_GInfo,rp,GREDRAW_UPDATE);
		ReleaseGIRPort(rp);
		retval=0;
		}
	}
return retval;
}

static ULONG mWrite(IClass *cl,Object *obj,dtWrite *msg)
{
return (msg->dtw_Mode==DTWM_IFF)?DoSuperMethodA(cl,obj,Msg(msg)):SaveRGFX(cl,obj,msg);
}

extern "C" ULONG Dispatcher(IClass *cl,Object *obj,Msg msg)
{
ULONG retval;
switch(msg->MethodID)
	{
	case OM_NEW:
		retval=mNew(cl,obj,(opSet *)msg);
		break;
	case OM_DISPOSE:
		retval=mDispose(cl,obj,msg);
		break;
	case OM_UPDATE:
		if(DoMethod(obj,ICM_CHECKLOOP)) break;
	case OM_SET:
		retval=mSet(cl,obj,(opSet *)msg);
		break;
	case DTM_WRITE:
		retval=mWrite(cl,obj,(dtWrite *)msg);
		break;
	default:
		retval=DoSuperMethodA(cl,obj,msg);
		}
return retval;
}

