< Aros < Developer < Docs < Libraries
Navbar for the Aros wikibook
Aros User
Aros User Docs
Aros User FAQs
Aros User Applications
Aros User DOS Shell
Aros/User/AmigaLegacy
Aros Dev Docs
Aros Developer Docs
Porting Software from AmigaOS/SDL
For Zune Beginners
Zune .MUI Classes
For SDL Beginners
Aros Developer BuildSystem
Specific platforms
Aros x86 Complete System HCL
Aros x86 Audio/Video Support
Aros x86 Network Support
Aros Intel AMD x86 Installing
Aros Storage Support IDE SATA etc
Aros Poseidon USB Support
x86-64 Support
Motorola 68k Amiga Support
Linux and FreeBSD Support
Windows Mingw and MacOSX Support
Android Support
Arm Raspberry Pi Support
PPC Power Architecture
misc
Aros Public License

Introduction

The datatypes.library was introduced to decode file formats (#?.png #?.jpg etc.) easily using different classes which can be installed as they are needed.

The descriptors in devs/datatypes contain the information how to identify a file type. Usually the file is opened only once by datatypes.library and a small buffer is used for comparisons which contains the first few bytes of the file (64 bytes IIRC).

dt descriptor is related to the struct DataTypeHeader dth_Name, dth_BaseName, etc.

Most datatype descriptors are held very simple, for example "compare the first 12 bytes with the pattern FORM????ILBM". The comparison is done by datatypes.library, there is no foreign code involved.

Only very few descriptors actually contain code. In this code everything can be done, though. For example, the code can close and reopen the file and read it entirely if needed. But this should not be done because identification needs to be very fast.

Dtdesc tool (and accompanied documentation) createdtdesc package is aimed at creating (picture) datatypes (as a whole, including makefiles). dtdescr is aimed at (only) viewing and creating the descriptor.

Once the file type is identified and the application wants to load the file, the class library from classes/datatypes is called. This library contains the code to decode the file contents and to make it available to datatypes.library.

Datatypes consist of a few libraries that exposes a couple of methods to load and save f.e. pictures of a certain type. Internally there is a 'common' storage method of the pixels that is used by the picture datatype, and so each 'library' that can handle its own type is able to 'convert' this common storage method into a specific format or load to this specific format.

The datatypes system itself exposes methods for the developer/user that allows for easy loading and saving by just calling some functions.

So, as long (and in theory) as there are 'libraries' that support a certain file-type (in this case pictures) you can very simply convert from one picture format to another picture format.

First you should learn about BOOPSI. If you understand BOOPSI, it's easy to understand datatypes, ReAction, MUI, ...

The only problem with AmigaOS implementation of datatypes is that they aren't really bidirectional. You can generally only save in IFF.

The ideal implementation would allow each datatype superclass (picture.datatype, sound.datatype etc.) to provide a list of all currently known sub-classes that support encoding. You'd then be able to pick one and encode data for that datatype and write it out to disk in that format.

Wanderer (AROS WB replacement) does not utilise the datatype subsystem directly "except" for loading window background imagery. The datatype system cannot deal with progressive loading and streaming yet.

assume you are trying to manipulate images? Load images using datatypes but read image data to ARGB array using ReadPixelArray methods and dispose source object. For images, to get the raw data use PDTM_READPIXELARRAY (that's the uncompressed data).

concerning Sounds ? Should it be better to use DTMethod to uncompress on a buffer and then use this uncompressed buffer ? For sound, get the data using the SDTA_Sample (or SDTA_LeftSample/SDTA_RightSample) attributes. You can retrieve sample data using SDTA_Sample tag but AmigaOS lacks support for SDTA_SampleType so you can get only 8-bit sample data there. AROS and MorphOS are more advanced there but generally it is better drop datatypes and write your own wave loader.

Setting SDTA_BitsPerSample, 16 will make SDTA_(Left|Right|%) Sample be in 16-bits (32-bit is also supported).

How to

create a Datatype Object, use the NewDTObject function ...

gd->gd_DisplayObject = NewDTObject ((IPTR)gd->gd_Unit, DTA_SourceType, DTST_CLIPBOARD, GA_Immediate, TRUE,
                                     GA_RelVerify, TRUE, DTA_TextAttr, (ULONG) & gd->gd_TextAttr, TAG_DONE)) 

The parameters of this functions uses Tags as defined in datatypes/datatypesclasses.h and intuition/gadgetclass.h

gf->gd_Unit = the Clipboard unit number
DTST_Clipboard = the Clipboard is the data source
GA_Immediate = Should the object be active when displayed
GA_RelVerify = Verify that the pointer is over the object when it is selected
gd_->gd_TextAttr = Pointer to text font attributes

Once a datatype object is no longer required, it is disposed of and memory released: e.g.

DisposeDTObject (gd->gd_DisplayObject);

To get attributes from a datatype object, you can use the GetDTAttrs function e.g.

GetDTAttrs (gd->gd_DisplayObject, DTA_DataType, (ULONG)&dtn, TAG_DONE);

and examining the results from the dtn structure you can retrieve:

dtn->dtn_Header->dth_Name = Descriptive name of the datatype
dtn->dtn_Header->dth_GroupID = The group the datatype belongs to

The function GetDTString returns a localised Datatypes string of the id given. This string could be syst, text, docu, soun, inst, musi, pict, anim or movi (see datatypes.h). e.g.

GetDTString (dtn->dtn_Header->dth_GroupID)

Change State - Set/Get

what you usually do is, to create an object (initial state), get/set some attributes (attribute change) and then do layout or extract a type.

in that case there many programs that call remap but doesn't have a gpinfo structure.

is there some info what remap have on initial state ?

AROS dt set it to true.

pd->Remap = TRUE;

when a program have no gpinfo with screen, then i think remap should be set to false.maybe AOS do that somewhere.

same can happen on AROS dt too, maybe on AOS dt bitmap (state change and get/set); however it is not clearly defined in which way state changes may affect attributes (screen, colors) or what happens in case some attributes have not been set prior triggering the state change; it's not even exactly clear which states are possible

Refresh

Your application can find out when a refresh is appropriate by using the Boopsi ICATarget attribute with the ICTargetIDCMP value. This causes the datatype (gadget) to send an IDCMP_IDCMPUpdate IntuiMessage to the window port on certain status changes. That message carries a pointer to one or more attributes and if DTA_Sync is in that list with a value of 1 then the datatype object is ready for refresh.

You get one of these on attaching the datatype object to your window, and also a stream of them when the window is resized.

Creating datatype object of specified subclass

In order to create a jpeg datatype object (jpeg subclass of picture class)

DTImage = NewDTObject(NULL,
DTA_SourceType, DTST_RAM,
DTA_BaseName, "jpeg",
PDTA_DestMode, PMODE_V43,
TAG_DONE);

Examples

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/datatypes.h>
#include <datatypes/pictureclass.h>

int main (void)

{
struct RDArgs *rdargs;
struct {
	char *file;
	char *pubscreen;
	} args = {0};

int rc = RETURN_FAIL;
struct Screen *scr;
Object *dto;
struct BitMapHeader *bmhd;
struct BitMap *bm;
WORD winw,winh;
struct Window *win;
struct IntuiMessage *imsg;
BOOL cont;

rdargs = ReadArgs ("FILE/A,PUBSCREEN/K",(LONG *)&args,NULL);
if (!rdargs)
	{
	PrintFault (IoErr(),NULL);
	return (RETURN_FAIL);
	}

if (scr = LockPubScreen (args.pubscreen))
	{

	if (dto = NewDTObject (args.file,DTA_GroupID,GID_PICTURE,PDTA_Remap,TRUE,PDTA_Screen,scr,TAG_END))
		{
		DoDTMethod (dto,NULL,NULL,DTM_PROCLAYOUT,NULL,TRUE);
		GetDTAttrs (dto,(ULONG) PDTA_BitMapHeader,&bmhd,(ULONG) PDTA_BitMap,&bm,TAG_END);

		if (bm && bmhd)
			{
			winw = bmhd->bmh_Width + scr->WBorLeft + scr->WBorRight;
			winh = bmhd->bmh_Height + scr->WBorTop + scr->RastPort.TxHeight + 1 + scr->WBorBottom;

			if (win = OpenWindowTags (NULL,
					WA_Left, (scr->Width - winw) / 2,
					WA_Top, (scr->Height - winh) / 2,
					WA_Width, winw,
					WA_Height, winh,
					WA_Title, args.file,
					WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_ACTIVATE | WFLG_NOCAREREFRESH,
					WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY,
					TAG_END))
				{
				rc = RETURN_OK;

				BltBitMapRastPort (bm,0,0,win->RPort,win->BorderLeft,win->BorderTop,win->GZZWidth,win->GZZHeight,0xc0);

				cont = TRUE;
				do	{
					if (Wait ((1L << win->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
						cont = FALSE;
					while (imsg = (struct IntuiMessage *) GetMsg (win->UserPort))
						{
						switch (imsg->Class)
							{
						case IDCMP_VANILLAKEY:
							if (imsg->Code == 0x1b) /* Esc */
								cont = FALSE;
							break;
						case IDCMP_CLOSEWINDOW:
							cont = FALSE;
							break;
							}
						ReplyMsg ((struct Message *) imsg);
						}
					}
				while (cont);
				CloseWindow (win);
				}

			}
		else
			Printf ("image cannot be rendered into the named pubscreen\n");

		DisposeDTObject (dto);
		}
	else
		{
		Printf (GetDTString (IoErr()),args.file);
		Printf ("\n");
		}

	UnlockPubScreen (NULL,scr);
	}
else
	Printf ("cannot lock pubscreen\n");

return (rc);
}

that's code of diskobjpngio.c.read

icon->iconPNG.handle = PNG_LoadImageMEM(icon->iconPNG.filebuffer, filesize,                                           chunknames, chunkpointer, TRUE);
    if (!icon->iconPNG.handle)
    {
        FreeIconPNG(&icon->dobj, IconBase);
    return FALSE;
    }
   
    {
        LONG width, height;
   
    PNG_GetImageInfo(icon->iconPNG.handle, &width, &height, NULL, NULL);
   
    icon->iconPNG.width  = width;
    icon->iconPNG.height = height;
    icon->iconPNG.transparency  = 0xffffffff;
    PNG_GetImageData(icon->iconPNG.handle, (APTR *)&icon->iconPNG.img1, NULL);

dt2thumb application

#include <dos/dos.h>
#include <dos/dosasl.h>
#include <dos/dosextens.h>
#include <dos/exall.h>
#include <dos/rdargs.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <utility/utility.h>

#include <proto/arossupport.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/cybergraphics.h>
#include <proto/datatypes.h>
#include <proto/icon.h>
#include <workbench/workbench.h>
#include <workbench/icon.h>
#include <datatypes/pictureclass.h>

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CTRL_C      (SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
#define  isDir(fib) ((fib)->fib_DirEntryType >= 0)

#define ARG_TEMPLATE    "FILE/A,ALL/S,QUIET/S,W=WIDTH/N,H=HEIGHT/N,F=FORCEASPECT/S,M=METHOD,DEFTOOL"

enum 
{
	ARG_FILE = 0,
	ARG_ALL,
	ARG_QUIET,
	ARG_WIDTH,
	ARG_HEIGHT,
	ARG_FORCEASPECT,
	ARG_METHOD,
	ARG_DEFTOOL,
	NOOFARGS
};

/* Maximum file path length */
#define MAX_PATH_LEN    2048

const TEXT version[] = "$VER: dt2thumb 1.1 (10.12.2010)\n";
static char cmdname[] = "dt2thumb";

typedef struct rgbImage
{
	UWORD Width;
	UWORD Height;
	UBYTE *Data;
}
RGBImage;

int doThumbs(struct AnchorPath *ap, STRPTR files, BOOL all, BOOL quiet,
		ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method);
BOOL CreateThumb(STRPTR infile, ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method);
BOOL readpic_by_datatype(RGBImage *pic, char *file_name);
BOOL savepic_by_datatype(RGBImage *pic, char *file_name);
RGBImage *resizeBilinear(RGBImage *pic, ULONG w2, ULONG h2);
RGBImage *resizeNearest(RGBImage *pic, ULONG w2, ULONG h2);
RGBImage *resizeAverage(RGBImage *pic, ULONG w2, ULONG h2);

int main(void)
{
	struct RDArgs      *rda = NULL;
	struct AnchorPath  *ap = NULL;
	int	   retval = RETURN_OK;
	
	STRPTR files = "#?";
	BOOL   all = FALSE;
	BOOL   quiet = FALSE;
	ULONG  destwidth = 128;
    ULONG  destheight = 128;
    BOOL   keepaspect = TRUE;
    STRPTR method = NULL;
    STRPTR deftool = NULL;
	IPTR   args[NOOFARGS] = { (IPTR)files, all, quiet, (IPTR)&destwidth, (IPTR)&destheight, !keepaspect ,(IPTR)method ,(IPTR)deftool};
	
	ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN, MEMF_ANY | MEMF_CLEAR);
	if (ap != NULL)
	{
		ap->ap_Strlen = MAX_PATH_LEN;
		
		rda = ReadArgs(ARG_TEMPLATE, args, NULL);

		if (rda != NULL)
		{
			/* Convert arguments into (less complex) variables */
			if (args[ARG_FILE])			files = (STRPTR)args[ARG_FILE];
			if (args[ARG_ALL])			all = TRUE;
			if (args[ARG_QUIET])		quiet = TRUE;
			if (args[ARG_WIDTH])		destwidth = (ULONG)*((IPTR *)args[ARG_WIDTH]);
			if (args[ARG_HEIGHT])		destheight = (ULONG)*((IPTR *)args[ARG_HEIGHT]);
			if (args[ARG_FORCEASPECT])	keepaspect = FALSE;
			if (args[ARG_METHOD])		method = (STRPTR)args[ARG_METHOD];
			if (args[ARG_DEFTOOL])		deftool = (STRPTR)args[ARG_DEFTOOL];

			if (!all &&IsDosEntryA(files, LDF_VOLUMES | LDF_DEVICES))
			{
				Printf("Can't create thumb for %s - ", files);
				SetIoErr(ERROR_OBJECT_WRONG_TYPE);
				PrintFault(IoErr(), NULL);

				retval = RETURN_FAIL;
			}
			else
				retval = doThumbs(ap, files, all, quiet, destwidth, destheight, keepaspect, deftool, method);
			
			FreeArgs(rda);
		}
		else
		{
			PrintFault(IoErr(), cmdname);
			retval = RETURN_FAIL;
		}
		
		if (ap!=NULL) FreeVec(ap);
	}
	else
	{
		retval = RETURN_FAIL;
	}
	
	return retval;
} /* main */

int doThumbs(struct AnchorPath *ap, STRPTR files, BOOL all, BOOL quiet,
			 ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method)
{
    LONG  match;
    int   retval = RETURN_OK;
    LONG  indent = 0;
    int   i;			/* Loop variable */
    BOOL  error;

    for (match = MatchFirst(files, ap);
    	 match == 0 && retval == RETURN_OK;// && !CTRL_C;
	     match = MatchNext(ap))
    {
		if (isDir(&ap->ap_Info))
		{
			if (ap->ap_Flags & APF_DIDDIR)
			{
				indent--;
				ap->ap_Flags &= ~APF_DIDDIR; /* Should not be necessary */
				continue;
			}
			else if (all)
			{
				ap->ap_Flags |= APF_DODIR;
				indent++;
			}
		}

		error = CreateThumb(ap->ap_Buf, destwidth, destheight, keepaspect, deftool, method);

        if (!quiet)
        {
            /* Fix indentation level */
            for (i = 0; i < indent; i++)
            {
                PutStr("     ");
            }

            if (!isDir(&ap->ap_Info))
            {
                PutStr("   ");
            }

            PutStr(ap->ap_Info.fib_FileName);

            if (isDir(&ap->ap_Info))
            {
                PutStr(" (dir)");
            }

            if (error)
            {
                PutStr(" ..Not a known picture file\n");
            }
            else
            {
                PutStr(" ..Thumbnail created\n");
            }
        }
    }

    MatchEnd(ap);

    return retval;
}

STRPTR get_ext(char *filename)
{
	static char extension[32];
	int position=strlen((char *)filename)-1;

	strcpy(extension,"");
	
	while(position > -1 && filename[position] != '.') position--;

	if (position > -1)
	{
		strncpy(extension,&filename[position+1],32);
	}

	return extension;
}

BOOL CreateThumb(STRPTR infile, ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method)
{
	RGBImage *in_pic = NULL, *out_pic = NULL;
	char outfile[MAX_PATH_LEN];
	BOOL retval = TRUE;

	// do not create thumb for info files
	if (strnicmp(get_ext(infile),"info",4)==0) return retval;

	sprintf(outfile,"%s.info",infile);

	if (in_pic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY))
	{
		in_pic->Data = NULL;
		if (readpic_by_datatype(in_pic, infile))
		{
			if (keepaspect)
			{
				int arw = in_pic->Width / destwidth;
				int arh = in_pic->Height / destheight;

				if (arw > arh) destheight = in_pic->Height / arw;
				else if (arh > arw) destwidth = in_pic->Width / arh;
			}
			
			if (method != NULL)
			{
				if (strnicmp(method,"BI",2)==0)
					out_pic = resizeBilinear(in_pic, destwidth, destheight);
				else if (strnicmp(method,"AV",2)==0)
					out_pic = resizeAverage(in_pic, destwidth, destheight);
				else
					out_pic = resizeNearest(in_pic, destwidth, destheight);
			}
			else
				out_pic = resizeNearest(in_pic, destwidth, destheight);
			
			if (out_pic)
			{
				if (savepic_by_datatype(out_pic, outfile))
				{
					// Write default tool
					struct DiskObject *icon = GetIconTags
					(
						infile, ICONGETA_FailIfUnavailable, FALSE, TAG_DONE
					);

					if (icon != NULL)
					{
						STRPTR oldDefaultTool = icon->do_DefaultTool;

						if (deftool)
							icon->do_DefaultTool = deftool;
						else
						{
							static STRPTR tool = "multiview";
							icon->do_DefaultTool = tool;
						}
						if (!PutIconTags(infile, icon, TAG_DONE))
						{
							Printf("ERROR: Failed to write icon.\n");
						}
						icon->do_DefaultTool = oldDefaultTool;
						
						FreeDiskObject(icon);
						
						retval = FALSE;
					}
					else
					{
						Printf("ERROR: Failed to open icon for file\n");
						retval = TRUE;;
					}			
				}
			}
		}
		if (in_pic)
		{
			if (in_pic->Data) FreeVec(in_pic->Data);
			FreeVec(in_pic);
		}
		if (out_pic)
		{
			if (out_pic->Data) FreeVec(out_pic->Data);
			FreeVec(out_pic);
		}
	}
		
	return retval;
}

BOOL readpic_by_datatype(RGBImage *pic, char *file_name)
{
	Object *DTImage = NULL;
	struct BitMapHeader *bmh;
	struct pdtBlitPixelArray bpa;

	DTImage = NewDTObject(	file_name,
							(DTA_SourceType),	DTST_FILE,
							(DTA_GroupID),		GID_PICTURE,
							(PDTA_Remap),		FALSE,
							(OBP_Precision),	PRECISION_EXACT,					
							TAG_DONE);

	if (DTImage)
	{

		if (GetDTAttrs( DTImage,
					PDTA_BitMapHeader, (ULONG)&bmh,
					TAG_END ) == 1)

		{

			/* Picture struct and buffer mem allocation */
			pic->Data = (UBYTE *)AllocVec(bmh->bmh_Width * bmh->bmh_Height * 4, MEMF_ANY);
			if (pic->Data)
			{
				bpa.MethodID = PDTM_READPIXELARRAY;
				bpa.pbpa_PixelData = (APTR)pic->Data;
				bpa.pbpa_PixelFormat = PBPAFMT_ARGB;
				bpa.pbpa_PixelArrayMod = bmh->bmh_Width * 4;
				bpa.pbpa_Left = 0;
				bpa.pbpa_Top = 0;
				bpa.pbpa_Width = bmh->bmh_Width;
				bpa.pbpa_Height = bmh->bmh_Height;

				DoMethodA( DTImage, (Msg)&bpa );

				pic->Width  = bmh->bmh_Width;
				pic->Height = bmh->bmh_Height;
				
				DisposeDTObject( DTImage );

				return TRUE;
			}
		}
		DisposeDTObject( DTImage );
	}
	return FALSE;
}

/**
* Nearest Neighbor resizing algorithm
* In case of thumbnail generation the loss of quality 
* should be minimal vs the bilinear algorithm
*/
RGBImage *resizeNearest(RGBImage *pic, ULONG w2, ULONG h2) 
{
	ULONG *temp = NULL;
	RGBImage *outpic = NULL;
	ULONG *pixels = (ULONG *)pic->Data;
    ULONG x_ratio = (ULONG)((pic->Width<<16)/w2) +1;
    ULONG y_ratio = (ULONG)((pic->Height<<16)/h2) +1;
    ULONG x2,y2,i,j;
	
	if (outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY))
	{
		outpic->Data = NULL;
		if (outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY))
		{
			outpic->Width = w2;
			outpic->Height = h2;
			temp = (ULONG *)outpic->Data;
			
			for (i=0;i<h2;i++)
			{
				y2 = ((i*y_ratio)>>16) ;
				for (j=0;j<w2;j++)
				{
					x2 = ((j*x_ratio)>>16) ;
					temp[(i*w2)+j] = pixels[(y2*pic->Width)+x2] ;
				}                
			}
		}
	}
    return outpic;
}

#define max(x,y) (x)>(y)?(x):(y)
#define min(x,y) (x)<(y)?(x):(y)

/**
* Averaging resizing algorithm
*  
* 
*/
RGBImage *resizeAverage(RGBImage *pic, ULONG w2, ULONG h2) 
{
	ULONG *temp = NULL;
	RGBImage *outpic = NULL;
	ULONG *pixels = (ULONG *)pic->Data;
	ULONG xpixels = min(256,max((ULONG)(pic->Width/w2),1));
	ULONG ypixels = min(256,max((ULONG)(pic->Height/h2),1));
    ULONG x_ratio = (ULONG)((pic->Width<<16)/w2) +1;
    ULONG y_ratio = (ULONG)((pic->Height<<16)/h2) +1;
	ULONG r,g,b,a,index;
    ULONG x2,y2,i,j,x,y;
	
	if (outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY))
	{
		outpic->Data = NULL;
		if (outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY))
		{
			outpic->Width = w2;
			outpic->Height = h2;
			temp = (ULONG *)outpic->Data;
			
			for (i=0;i<h2;i++)
			{
				y2 = ((i*y_ratio)>>16) ;
				for (j=0;j<w2;j++)
				{
					x2 = ((j*x_ratio)>>16) ;
					
					r = 0;
					g = 0;
					b = 0;
					a = 0;
					
					for (y=0;y<ypixels;y++)
						for (x=0;x<xpixels;x++)
						{
							index = ((y2+y)*pic->Width+(x2+x));
							b += (pixels[index]&0xff);
							g += ((pixels[index]>>8)&0xff);
							r += ((pixels[index]>>16)&0xff);
							a += ((pixels[index]>>24)&0xff);
						}
						
					r /= (ypixels*xpixels);
					g /= (ypixels*xpixels);
					b /= (ypixels*xpixels);
					a /= (ypixels*xpixels);
						
					temp[(i*w2)+j] = 	((((ULONG)a)<<24) & 0xff000000) |
										((((ULONG)r)<<16) & 0x00ff0000) |
										((((ULONG)g)<<8)  & 0x0000ff00) |
										((ULONG)b) ;					
				}                
			}
		}
	}
    return outpic;
}

/**
* Bilinear resize ARGB image.
* pixels is an array of size w * h.
* Target dimension is w2 * h2.
* w2 * h2 cannot be zero.
*/
RGBImage *resizeBilinear(RGBImage *pic, ULONG w2, ULONG h2) 
{
	ULONG *temp = NULL;
	RGBImage *outpic = NULL;
	ULONG *pixels = (ULONG *)pic->Data;
	ULONG a, b, c, d, x, y, index ;
	float x_ratio = ((float)(pic->Width-1))/w2 ;
	float y_ratio = ((float)(pic->Height-1))/h2 ;
	float x_diff, y_diff, blue, red, green, alpha ;
	ULONG offset = 0 ;
	int i,j;
	
	if (outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY))
	{
		if (outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY))
		{
			outpic->Width = w2;
			outpic->Height = h2;
			temp = (ULONG *)outpic->Data;
	
			if ((pic->Width==w2) && (pic->Height=h2))
			{
				CopyMem(pixels, temp, pic->Width * pic->Height * 4);
				return outpic;
			}
			
			for (i=0;i<h2;i++) 
			{
				for (j=0;j<w2;j++)
				{
					x = (ULONG)(x_ratio * j) ;
					y = (ULONG)(y_ratio * i) ;
					x_diff = (x_ratio * j) - x ;
					y_diff = (y_ratio * i) - y ;
					index = (y*pic->Width+x) ;                
					a = pixels[index] ;
					b = pixels[index+1] ;
					c = pixels[index+pic->Width] ;
					d = pixels[index+pic->Width+1] ;

					// blue element
					// Yb = Ab(1-w)(1-h) + Bb(w)(1-h) + Cb(h)(1-w) + Db(wh)
					blue = (a&0xff)*(1-x_diff)*(1-y_diff) + (b&0xff)*(x_diff)*(1-y_diff) +
					(c&0xff)*(y_diff)*(1-x_diff)   + (d&0xff)*(x_diff*y_diff);

					// green element
					// Yg = Ag(1-w)(1-h) + Bg(w)(1-h) + Cg(h)(1-w) + Dg(wh)
					green = ((a>>8)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>8)&0xff)*(x_diff)*(1-y_diff) +
					((c>>8)&0xff)*(y_diff)*(1-x_diff)   + ((d>>8)&0xff)*(x_diff*y_diff);

					// red element
					// Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
					red = ((a>>16)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>16)&0xff)*(x_diff)*(1-y_diff) +
					((c>>16)&0xff)*(y_diff)*(1-x_diff)   + ((d>>16)&0xff)*(x_diff*y_diff);

					// alpha element
					// Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
					alpha = ((a>>24)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>24)&0xff)*(x_diff)*(1-y_diff) +
					((c>>24)&0xff)*(y_diff)*(1-x_diff)   + ((d>>24)&0xff)*(x_diff*y_diff);

					
					temp[offset++] = 	((((ULONG)alpha)<<24) & 0xff000000) |
										((((ULONG)red)  <<16) & 0x00ff0000) |
										((((ULONG)green)<<8)  & 0x0000ff00) |
										((ULONG)blue) ;
				}
			}
		}
	}
	return outpic ;
}

BOOL savepic_by_datatype(RGBImage *pic, char *file_name)
{
	Object *DTImage = NULL;
	struct BitMapHeader *bmhd;
	struct dtWrite dtw;
	struct pdtBlitPixelArray dtb;
	FILE *file = NULL;
	BOOL retval = FALSE;
	
	DTImage = NewDTObject(	(APTR)NULL,
							DTA_SourceType, DTST_RAM,
							DTA_BaseName, (IPTR)"png",
							PDTA_DestMode, PMODE_V43,
							TAG_DONE);
	if (!DTImage) return(FALSE);

	if (GetDTAttrs(DTImage,PDTA_BitMapHeader,(IPTR)&bmhd,TAG_DONE))
	{
		dtb.MethodID = PDTM_WRITEPIXELARRAY;
		dtb.pbpa_PixelData = pic->Data;
		dtb.pbpa_PixelFormat = PBPAFMT_ARGB;
		dtb.pbpa_PixelArrayMod = pic->Width*4;
		dtb.pbpa_Left = 0;
		dtb.pbpa_Top = 0;
		dtb.pbpa_Width = pic->Width;
		dtb.pbpa_Height = pic->Height;

		bmhd->bmh_Width = pic->Width;
		bmhd->bmh_Height = pic->Height;
		bmhd->bmh_Depth = 24;
		bmhd->bmh_PageWidth = 320;
		bmhd->bmh_PageHeight = 240;
		
		DoMethodA(DTImage, (Msg) &dtb);

		//write datatype object to file
		if (file = Open (file_name,MODE_NEWFILE))
		{
			dtw.MethodID = DTM_WRITE;
			dtw.dtw_GInfo = NULL;
			dtw.dtw_FileHandle = file;
			dtw.dtw_Mode = DTWM_RAW;
			dtw.dtw_AttrList = NULL;

			if (DoMethodA(DTImage, (Msg) &dtw)) retval = TRUE;
		}
	}

	if (file) Close (file);
	if (DTImage) DisposeDTObject(DTImage);
	return retval;
}

sound function

void do_sound()
{
    soundnow = "sounds/bingobongo.aiff";

    cout << "do sound!"<<endl;
    int frq, vol, pan, state;

    if (soundobject)DisposeDTObject(soundobject);

    if ((soundobject = NewDTObject(soundnow,
        DTA_SourceType,    DTST_FILE,
        DTA_GroupID,       GID_SOUND,
        DTA_Repeat,        TRUE,
        SDTA_SignalTask,   (ULONG) FindTask(NULL),
        SDTA_SignalBit,    (ULONG) SIGBREAKF_CTRL_C,
        TAG_DONE)))
    {
        
        
            DoDTMethod(soundobject, NULL, NULL, DTM_TRIGGER, NULL, STM_PLAY, NULL);

    }
    else
    {
        cout << "can't create sound"<<endl;
    }
}

STATIC IPTR DT_SetMethod(struct IClass *cl, struct Gadget *g, struct opSet *msg)
{
    struct Picture_Data *pd;
    const struct TagItem *tl = msg->ops_AttrList;
    struct TagItem *ti;
    IPTR RetVal;
    struct RastPort *rp;

    pd=(struct Picture_Data *) INST_DATA(cl, g);
    RetVal=0;

    while((ti=NextTagItem(&tl)))
    {
        switch (ti->ti_Tag)
        {
        case DTA_VisibleHoriz:
        case DTA_VisibleVert:
            RetVal = 1;
        break;
       
            case PDTA_ModeID:
                pd->ModeID = (ULONG) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_ModeID: 0x%lx\n",(long)pd->ModeID));
                break;

            case PDTA_ClassBitMap:
                pd->KeepSrcBM = TRUE;
            DGS(bug("picture.datatype/OM_GET: Tag PDTA_ClassBitMap: Handled as PDTA_BitMap\n"));
            case PDTA_BitMap:
                pd->SrcBM = (struct BitMap *) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_BitMap: 0x%lx\n",(long)pd->SrcBM));
                break;

            case PDTA_Screen:
                pd->DestScreen = (struct Screen *) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_Screen: 0x%lx\n",(long)pd->DestScreen));
                break;

            case PDTA_NumColors:
                pd->NumColors = (UWORD) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_NumColors:%ld\n", (long)pd->NumColors));
                break;

            case PDTA_Grab:
            {
                Point *ThePoint;

                DGS(bug("picture.datatype/OM_SET: Tag PDTA_Grab\n"));
                ThePoint = (Point *) ti->ti_Data;
                if(!ThePoint)
                {
                 break;
                }
                pd->Grab.x = ThePoint->x;
                pd->Grab.y = ThePoint->y;
                break;
            }

        case PDTA_SourceMode:
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_SourceMode (ignored): %ld\n", (long)ti->ti_Data));
            break;

        case PDTA_DestMode:
        pd->DestMode = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_DestMode: %ld\n",(long)pd->DestMode));
            break;

            case PDTA_FreeSourceBitMap:
                pd->FreeSource = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_FreeSourceBitMap:%ld\n", (long)pd->FreeSource));
                break;

        case PDTA_UseFriendBitMap:
                pd->UseFriendBM = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_UseFriendBitMap:%ld\n", (long)pd->UseFriendBM));
            break;

        case PDTA_MaxDitherPens:
                pd->MaxDitherPens = (UWORD) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_MaxDitherPens:%ld\n", (long)pd->MaxDitherPens));
            break;

        case PDTA_DitherQuality:
                pd->DitherQuality = (UWORD) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_DitherQuality:%ld\n", (long)pd->DitherQuality));
            break;

        case PDTA_ScaleQuality:
                pd->ScaleQuality = (UWORD) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_ScaleQuality:%ld\n", (long)pd->ScaleQuality));
            break;

            case PDTA_Remap:               
                pd->Remap = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag ID PDTA_Remap: %ld\n",(long)pd->Remap));
                break;   
       
#ifdef __AROS__
        case PDTA_DelayedRead:
                pd->DelayedRead = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_DelayedRead:
%ld\n", (long)pd->DelayedRead));
            break;
#endif

#ifdef MYDEBUG
            default:
            {
             register int i;
             int Known;

             Known=FALSE;

             for(i=0; i<NumAttribs; i++)
             {
              if(ti->ti_Tag==KnownAttribs[i])
              {
               Known=TRUE;

               DGS(bug("picture.datatype/OM_SET: Tag %s: 0x%lx (%ld)\n",AttribNames[i], (long)ti->ti_Data, (long)ti->ti_Data));
              }
             }

             if(!Known)
             {
              DGS(bug("picture.datatype/OM_SET: Tag ID 0x%lx: 0x%lx\n",(long)ti->ti_Tag, (long)ti->ti_Data));
             }
            }
#endif /* MYDEBUG */
        }
    }

#if 0
    if(msg->ops_GInfo)
    {
        DoMethod((Object *) g, GM_LAYOUT, msg->ops_GInfo, TRUE);
    }
#endif

    /* Do not call the SuperMethod if you come from OM_NEW! */
    if(!(msg->MethodID == OM_NEW))
    {
        RetVal += (IPTR) DoSuperMethodA(cl, (Object *) g, (Msg) msg);
    }

    if(msg->ops_GInfo)
    {
#if 1
        if (RetVal)
#else
        if(OCLASS((Object *) g) == cl)
#endif
        {
            rp=ObtainGIRPort(msg->ops_GInfo);
            if(rp)
            {
                DoMethod((Object *) g, GM_RENDER, (IPTR) msg->ops_GInfo,(IPTR) rp, GREDRAW_UPDATE);
                ReleaseGIRPort (rp);
            }
        }

#if 0 /* stegerg: ?? */
        if(msg->MethodID == OM_UPDATE)
        {
             DoMethod((Object *) g, OM_NOTIFY, msg->ops_AttrList,
msg->ops_GInfo, 0);
        }
#endif
    }

    return(RetVal);
}

---------------------------------------------------

STATIC IPTR DT_Render(struct IClass *cl, struct Gadget *g, struct gpRender *msg)
{
    struct Picture_Data *pd;
    struct DTSpecialInfo *si;

    struct IBox *domain;
    IPTR TopVert, TopHoriz;

    long SrcX, SrcY, DestX, DestY, SizeX, SizeY;

    pd = (struct Picture_Data *) INST_DATA(cl, g);
    si = (struct DTSpecialInfo *) g->SpecialInfo;

    if(!pd->Layouted)
    {
        D(bug("picture.datatype/GM_RENDER: No layout done yet !\n"));
        return FALSE;
    }

    if(si->si_Flags & DTSIF_LAYOUT)
    {
        D(bug("picture.datatype/GM_RENDER: In layout process !\n"));
        return FALSE;
    }

    if(!(GetDTAttrs((Object *) g, DTA_Domain,    (IPTR) &domain,
                   DTA_TopHoriz,     (IPTR) &TopHoriz,
                   DTA_TopVert,      (IPTR) &TopVert,
                   TAG_DONE) == 3))
    {
        D(bug("picture.datatype/GM_RENDER: Couldn't get dimensions\n"));
        return FALSE;
    }

    ObtainSemaphore(&(si->si_Lock));
    D(bug("picture.datatype/GM_RENDER: Domain: left %ld top %ld width %ld height %ld\n", domain->Left, domain->Top, domain->Width, domain->Height));
    D(bug("picture.datatype/GM_RENDER: TopHoriz %ld TopVert %ld Width %ld Height %ld\n", (long)TopHoriz, (long)TopVert, (long)pd->DestWidth, (long)pd->DestHeight));

    if( pd->DestBM )
    {
    SrcX = MIN( TopHoriz, pd->DestWidth );
    SrcY = MIN( TopVert, pd->DestHeight );
    DestX = domain->Left;
    DestY = domain->Top;
    SizeX = MIN( pd->DestWidth - SrcX, domain->Width );
    SizeY = MIN( pd->DestHeight - SrcY, domain->Height );
    D(bug("picture.datatype/GM_RENDER: SizeX/Y %ld/%ld\n SrcX/Y %ld/%ld DestX/Y %ld/%ld\n",
        SizeX, SizeY, SrcX, SrcY, DestX, DestY));

    render_on_rastport(pd, g, SrcX, SrcY, msg->gpr_RPort, DestX, DestY, SizeX, SizeY);
    }
    else /* if(pd->DestBuffer) || if(pd->DestBM) */
    {
        D(bug("picture.datatype/GM_RENDER: No destination picture present !\n"));
        return FALSE;
    }
    ReleaseSemaphore(&(si->si_Lock));

    return TRUE;
}

How to compile datatypes

Build dtdesc tool, this is what you need. The source is located in tools/dtdesc. This tool is used in order to make a datatype descriptor from .dtd file. Class library is built in a usual way, using a usual crosscompiler.

A package so that it will be easy to build datatypes independently of the whole build system. Compiled createdtdesc and examinedtdesc for native AROS. One other tool that is needed is genmodule.

What is needed is a READ/WRITEPIXELARRAY interface, that replaces the former SET PDTA_BitMap and GET PDTA_DestBitMap interface. If a Bitmap was SET (legacy interface), it gets converted to LUT8 format during layout. A destination BitMap is only created, if this is set by Prefs or an applications requests it by GET PDTA_DestBitMap.

RENDER Method chooses one of these functions for displaying

  • cgfx/WritePixelArray: Truecolor pic -> Truecolor screen
  • cgfx/WriteLUTPixelArray: Colormapped pic -> Truecolor screen
  • graphics/WriteChunkyPixels: Colormapped pic -> Colormapped chunky screen
  • graphics/BltBitMapRastPort: Colormapped pic -> Colormapped planar screen

Truecolor pic -> Colormapped screen is handled during layout, with a fixed colormap and some simple but fast dithering algorithm (one dimensional error propagation). Floyd-Steinberg dithering algorithm could be used for slightly better results (two dimensional error propagation). Much better results could be obtained by a calculated colormap (e.g. median cut algorithm), but this is much slower.

Colormapped data is always stored in LUT8 format, or BitMap format for legacy. Truecolor data is always stored in ARGB format. This isn't memory effective, but makes things more simple and faster. Some optimization could be done here.

Created a template for new graphic datatypes here.

/*
    Copyright © 1995-2005, The AROS Development Team. All rights reserved.
    $Id: bmpclass.c 30902 2009-03-14 13:38:20Z mazze $
*/

/**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dostags.h>
#include <graphics/gfxbase.h>
#include <graphics/rpattr.h>
#include <cybergraphx/cybergraphics.h>
#include <intuition/imageclass.h>
#include <intuition/icclass.h>
#include <intuition/gadgetclass.h>
#include <intuition/cghooks.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>

#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/iffparse.h>
#include <proto/datatypes.h>

#include <aros/symbolsets.h>

#include "debug.h"

#include "methods.h"

/* Open superclass */
ADD2LIBS("datatypes/picture.datatype", 0, struct Library *, PictureBase);

/**************************************************************************************************/

#define FILEBUFSIZE 65536
#define MAXCOLORS   256

typedef struct {
    struct IFFHandle    *filehandle;

    UBYTE               *filebuf;
    UBYTE               *filebufpos;
    long                filebufbytes;
    long                filebufsize;
    UBYTE               *linebuf;
    UBYTE               *linebufpos;
    long                linebufbytes;
    long                linebufsize;
    
    APTR                codecvars;
} BmpHandleType;

typedef struct
{
    WORD        bfType;             //  0 ASCII "BM"
    ULONG       bfSize;             //  2 Size in bytes of the file
    WORD        bfReserved1;        //  6 Zero
    WORD        bfReserved2;        //  8 Zero
    ULONG       bfOffBits;          // 10 Byte offset in files where image begins
} FileBitMapHeader __attribute__((packed));    // 14

typedef struct
{
    ULONG       biSize;             //  0 Size of this header, 40 bytes
    LONG        biWidth;            //  4 Image width in pixels
    LONG        biHeight;           //  8 Image height in pixels
    WORD        biPlanes;           // 12 Number of image planes, must be 1
    WORD        biBitCount;         // 14 Bits per pixel, 1, 4, 8, 24, or 32
    ULONG       biCompression;      // 16 Compression type, below
    ULONG       biSizeImage;        // 20 Size in bytes of compressed image, or zero
    LONG        biXPelsPerMeter;    // 24 Horizontal resolution, in pixels/meter
    LONG        biYPelsPerMeter;    // 28 Vertical resolution, in pixels/meter
    ULONG       biClrUsed;          // 32 Number of colors used, below
    ULONG       biClrImportant;     // 36 Number of "important" colors
} BitmapInfoHeader __attribute__((packed));    // 40

/* "BM" backwards, due to LE byte order */
#define BITMAP_ID "MB"

/**************************************************************************************************/

static void BMP_Exit(BmpHandleType *bmphandle, LONG errorcode)
{
    D(if (errorcode) bug("bmp.datatype/BMP_Exit() --- IoErr %ld\n", errorcode));
    if (bmphandle->filebuf)
    {
	FreeMem(bmphandle->filebuf, bmphandle->filebufsize);
    }
    if (bmphandle->linebuf)
    {
	FreeMem(bmphandle->linebuf, bmphandle->linebufsize);
    }
    if (bmphandle->codecvars)
    {
	FreeVec(bmphandle->codecvars);
    }
    SetIoErr(errorcode);
}

/**************************************************************************************************/

/* buffered file access, useful for RLE */
BOOL SaveBMP_EmptyBuf(BmpHandleType *bmphandle, long minbytes)
{
    long                bytes, bytestowrite;
    
    bytestowrite = bmphandle->filebufsize - (bmphandle->filebufbytes + minbytes);
    D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- minimum %ld bytes, %ld bytes to write\n", (long)minbytes, (long)bytestowrite));
    bytes = Write(bmphandle->filehandle, bmphandle->filebuf, bytestowrite);
    if ( bytes < bytestowrite )
    {
	D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- writing failed, wrote %ld bytes\n", (long)bytes));
	return FALSE;
    }
    bmphandle->filebufpos = bmphandle->filebuf;
    bmphandle->filebufbytes = bmphandle->filebufsize - minbytes;
    D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- wrote %ld bytes\n", (long)bytes));
    return TRUE;
}

/* buffered file access, useful for RLE */
BOOL LoadBMP_FillBuf(BmpHandleType *bmphandle, long minbytes)
{
    long                i, bytes;
    
    //D(bug("bmp.datatype/LoadBMP_FillBuf() --- minimum %ld bytes of %ld (%ld) bytes\n", (long)minbytes, (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
    if ( bmphandle->filebufbytes >= 0 )
	return TRUE;
    bytes = bmphandle->filebufbytes + minbytes;
    //D(bug("bmp.datatype/LoadBMP_FillBuf() --- %ld bytes requested, %ld bytes left\n", (long)minbytes, (long)bytes));
    if (bytes > 0)
    {
	//D(bug("bmp.datatype/LoadBMP_FillBuf() --- existing %ld old bytes\n", (long)bytes));
	for (i=0; i<bytes; i++)     /* copy existing bytes to start of buffer */
	    bmphandle->filebuf[i] = bmphandle->filebufpos[i];
    }
    bmphandle->filebufpos = bmphandle->filebuf;
    bytes = Read(bmphandle->filehandle, bmphandle->filebuf + bytes, bmphandle->filebufsize - bytes);
    if (bytes < 0 ) bytes = 0;
    bmphandle->filebufbytes += bytes;
    //D(bug("bmp.datatype/LoadBMP_FillBuf() --- read %ld bytes, remaining new %ld bytes\n", (long)bytes, (long)bmphandle->filebufbytes));
    //D(bug("bmp.datatype/LoadBMP_FillBuf() --- >minimum %ld bytes of %ld (%ld) bytes\n", (long)minbytes, (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
    if (bmphandle->filebufbytes >= 0)
	return TRUE;
    return FALSE;
}

static BOOL LoadBMP_Colormap(BmpHandleType *bmphandle, int numcolors,
			    struct ColorRegister *colormap, ULONG *colregs)
{
    unsigned int        i, j;

    if (numcolors && numcolors <= MAXCOLORS)
    {
	j = 0;
	for (i = 0; i < numcolors; i++)
	{
	    if ( (bmphandle->filebufbytes -= 4) < 0 && !LoadBMP_FillBuf(bmphandle, 4) )
	    {
		D(bug("bmp.datatype/LoadBMP_Colormap() --- colormap loading failed\n"));
		return FALSE;
	    }
	    /* BGR0 format for MS Win files, BGR format for OS/2 files */
	    colormap[i].blue = *(bmphandle->filebufpos)++;
	    colormap[i].green = *(bmphandle->filebufpos)++;
	    colormap[i].red = *(bmphandle->filebufpos)++;
	    bmphandle->filebufpos++;
	    colregs[j++] = ((ULONG)colormap[i].red)<<24;
	    colregs[j++] = ((ULONG)colormap[i].green)<<24;
	    colregs[j++] = ((ULONG)colormap[i].blue)<<24;
	    // D(if (i<5) bug("gif r %02lx g %02lx b %02lx\n", colormap[i].red, colormap[i].green, colormap[i].blue));
	}
	D(bug("bmp.datatype/LoadBMP_Colormap() --- %d colors loaded\n", numcolors));
    }
    return TRUE;
}

/**************************************************************************************************/
static BOOL LoadBMP(struct IClass *cl, Object *o)
{
    BmpHandleType           *bmphandle;
    UBYTE                   *filebuf;
    IPTR                    sourcetype;
    ULONG                   bfSize, bfOffBits;
    ULONG                   biSize, biWidth, biHeight, biCompression;
    ULONG                   biClrUsed, biClrImportant;
    UWORD                   biPlanes, biBitCount;
    ULONG                   alignwidth, alignbytes, pixelfmt;
    long                    x, y;
    int                     cont, byte;
    struct BitMapHeader     *bmhd;
    struct ColorRegister    *colormap;
    ULONG                   *colorregs;
    STRPTR                  name;

    D(bug("bmp.datatype/LoadBMP()\n"));

    if( !(bmphandle = AllocMem(sizeof(BmpHandleType), MEMF_ANY)) )
    {
	SetIoErr(ERROR_NO_FREE_STORE);
	return FALSE;
    }
    bmphandle->filebuf = NULL;
    bmphandle->linebuf = NULL;
    bmphandle->codecvars = NULL;
    
    
    if( GetDTAttrs(o,   DTA_SourceType    , (IPTR)&sourcetype ,
			DTA_Handle        , (IPTR)&(bmphandle->filehandle),
			PDTA_BitMapHeader , (IPTR)&bmhd,
			TAG_DONE) != 3 )
    {
	BMP_Exit(bmphandle, ERROR_OBJECT_NOT_FOUND);
	return FALSE;
    }
    
    if ( sourcetype == DTST_RAM && bmphandle->filehandle == NULL && bmhd )
    {
	D(bug("bmp.datatype/LoadBMP() --- Creating an empty object\n"));
	BMP_Exit(bmphandle, 0);
	return TRUE;
    }
    if ( sourcetype != DTST_FILE || !bmphandle->filehandle || !bmhd )
    {
	D(bug("bmp.datatype/LoadBMP() --- unsupported mode\n"));
	BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
	return FALSE;
    }
    
    /* initialize buffered file reads */
    bmphandle->filebufbytes = 0;
    bmphandle->filebufsize = FILEBUFSIZE;
    if( !(bmphandle->filebuf = bmphandle->filebufpos = AllocMem(bmphandle->filebufsize, MEMF_ANY)) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }

    /* load FileBitmapHeader from file, make sure, there are at least 14 bytes in buffer */
    if ( (bmphandle->filebufbytes -= 14) < 0 && !LoadBMP_FillBuf(bmphandle, 14) )
    {
	D(bug("bmp.datatype/LoadBMP() --- filling buffer with header failed\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    filebuf = bmphandle->filebufpos;    /* this makes things easier */
    bmphandle->filebufpos += 14;
    if( filebuf[0] != 'B' && filebuf[1] != 'M' )
    {
	D(bug("bmp.datatype/LoadBMP() --- header type mismatch\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    /* byte-wise access isn't elegant, but it is endianess-safe */
    bfSize = (filebuf[5]<<24) | (filebuf[4]<<16) | (filebuf[3]<<8) | filebuf[2];
    bfOffBits = (filebuf[13]<<24) | (filebuf[12]<<16) | (filebuf[11]<<8) | filebuf[10];
    D(bug("bmp.datatype/LoadBMP() --- bfSize %ld bfOffBits %ld\n", bfSize, bfOffBits));

    /* load BitmapInfoHeader from file, make sure, there are at least 40 bytes in buffer */
    if ( (bmphandle->filebufbytes -= 40) < 0 && !LoadBMP_FillBuf(bmphandle, 40) )
    {
	D(bug("bmp.datatype/LoadBMP() --- filling buffer with header 2 failed\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    filebuf = bmphandle->filebufpos;    /* this makes things easier */
    bmphandle->filebufpos += 40;

    /* get image size attributes */
    biSize = (filebuf[3]<<24) | (filebuf[2]<<16) | (filebuf[1]<<8) | filebuf[0];
    biWidth = (filebuf[7]<<24) | (filebuf[6]<<16) | (filebuf[5]<<8) | filebuf[4];
    biHeight = (filebuf[11]<<24) | (filebuf[10]<<16) | (filebuf[9]<<8) | filebuf[8];
    biPlanes = (filebuf[13]<<8) | filebuf[12];
    biBitCount = (filebuf[15]<<8) | filebuf[14];
    biCompression = (filebuf[19]<<24) | (filebuf[18]<<16) | (filebuf[17]<<8) | filebuf[16];
    biClrUsed = (filebuf[35]<<24) | (filebuf[34]<<16) | (filebuf[33]<<8) | filebuf[32];
    biClrImportant = (filebuf[39]<<24) | (filebuf[38]<<16) | (filebuf[37]<<8) | filebuf[36];
    D(bug("bmp.datatype/LoadBMP() --- BMP-Screen %ld x %ld x %ld, %ld (%ld) colors, compression %ld, type %ld\n",
	  biWidth, biHeight, (long)biBitCount, biClrUsed, biClrImportant, biCompression, biSize));
    if (biSize != 40 || biPlanes != 1 || biCompression != 0)
    {
	D(bug("bmp.datatype/LoadBMP() --- Image format not supported\n"));
	BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
	return FALSE;
    }

    /* check color mode */
    pixelfmt = PBPAFMT_LUT8;
    switch (biBitCount)
    {
	case 1:
	    alignwidth = (biWidth + 31) & ~31UL;
	    alignbytes = alignwidth / 8;
	    break;
	case 4:
	    alignwidth = (biWidth + 7) & ~7UL;
	    alignbytes = alignwidth / 2;
	    break;
	case 8:
	    alignwidth = (biWidth + 3) & ~3UL;
	    alignbytes = alignwidth;
	    break;
	case 24:
	    alignbytes = (biWidth + 3) & ~3UL;
	    alignwidth = alignbytes * 3;
	    pixelfmt = PBPAFMT_RGB;
	    break;
	default:
	    D(bug("bmp.datatype/LoadBMP() --- unsupported color depth\n"));
	    BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
	    return FALSE;
    }
    D(bug("bmp.datatype/LoadBMP() --- align: pixels %ld bytes %ld\n", alignwidth, alignbytes));

    /* set BitMapHeader with image size */
    bmhd->bmh_Width  = bmhd->bmh_PageWidth  = biWidth;
    bmhd->bmh_Height = bmhd->bmh_PageHeight = biHeight;
    bmhd->bmh_Depth  = biBitCount;

    /* get empty colormap, then fill in colormap to use*/
    if (biBitCount != 24)
    {
	if( !(GetDTAttrs(o, PDTA_ColorRegisters, (IPTR)&colormap,
			    PDTA_CRegs, (IPTR)&colorregs,
			    TAG_DONE ) == 2) ||
	    !(colormap && colorregs) )
	{
	    D(bug("bmp.datatype/LoadBMP() --- got no colormap\n"));
	    BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	    return FALSE;
	}
	if( !LoadBMP_Colormap(bmphandle, biClrUsed, colormap, colorregs) )
	{
	    BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	    return FALSE;
    }
    }
    /* skip offset */
    bfOffBits = bfOffBits - 14 - 40 - biClrUsed*4;
    D(bug("bmp.datatype/LoadBMP() --- remaining offset %ld\n", bfOffBits));
    if ( bfOffBits < 0 ||
	( (bmphandle->filebufbytes -= bfOffBits ) < 0 && !LoadBMP_FillBuf(bmphandle, bfOffBits) ) )
    {
	D(bug("bmp.datatype/LoadBMP() --- cannot skip offset\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    bmphandle->filebufpos += bfOffBits;

    /* Pass attributes to picture.datatype */
    GetDTAttrs( o, DTA_Name, (IPTR)&name, TAG_DONE );
    SetDTAttrs(o, NULL, NULL, PDTA_NumColors, biClrUsed,
			      DTA_NominalHoriz, biWidth,
			      DTA_NominalVert , biHeight,
			      DTA_ObjName     , (IPTR)name,
			      TAG_DONE);

    /* Now decode the picture data into a chunky buffer; and pass it to Bitmap line-by-line */
    bmphandle->linebufsize = bmphandle->linebufbytes = alignwidth;
    if (! (bmphandle->linebuf = bmphandle->linebufpos = AllocMem(bmphandle->linebufsize, MEMF_ANY)) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }

    //D(bug("bmp.datatype/LoadBMP() --- bytes of %ld (%ld) bytes\n", (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
    cont = 1;
    for (y=biHeight-1; y>=0 && cont; y--)
    {
	int r, g, b;
	
	bmphandle->linebufpos = bmphandle->linebuf;
	if (biBitCount == 24)
	{
	    if ( (bmphandle->filebufbytes -= alignwidth) < 0 && !LoadBMP_FillBuf(bmphandle, alignwidth) )
	    {
		D(bug("bmp.datatype/LoadBMP() --- early end of bitmap data, x %ld y %ld\n", x, y));
		//BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
		//return FALSE;
		cont = 0;
	    }
	    for (x=0; x<alignbytes; x++)
	    {
		b = *(bmphandle->filebufpos)++;
		g = *(bmphandle->filebufpos)++;
		r = *(bmphandle->filebufpos)++;
		*(bmphandle->linebufpos)++ = r;
		*(bmphandle->linebufpos)++ = g;
		*(bmphandle->linebufpos)++ = b;
	    }
	}
	else
	{
	    for (x=0; x<alignbytes; x++)
	    {
		if ( (bmphandle->filebufbytes -= 1) < 0 && !LoadBMP_FillBuf(bmphandle, 1) )
		{
		    D(bug("bmp.datatype/LoadBMP() --- early end of bitmap data, x %ld y %ld\n", x, y));
		    //BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
		    //return FALSE;
		    cont = 0;
		    break;              
		}
		byte = *(bmphandle->filebufpos)++;
		switch (biBitCount)
		{
		    case 1:
			for (b=0; b<8; b++)
			{
			    *(bmphandle->linebufpos)++ = (byte & 0x80) ? 1 : 0;
			    byte <<= 1;
			}
			break;
		    case 4:
			*(bmphandle->linebufpos)++ = (byte & 0xf0) >> 4;
			*(bmphandle->linebufpos)++ = (byte & 0x0f);
			break;
		    case 8:
			*(bmphandle->linebufpos)++ = byte;
			break;
		    case 24:
			*(bmphandle->linebufpos)++ = byte;
			break;
		}
	    }
	}
	if
	(
	    !DoSuperMethod(cl, o,
			   PDTM_WRITEPIXELARRAY,	/* Method_ID */
			   (IPTR)bmphandle->linebuf,	/* PixelData */
			   pixelfmt,			/* PixelFormat */
			   alignwidth,			/* PixelArrayMod (number of bytes per row) */
			   0,				/* Left edge */
			   y,				/* Top edge */
			   biWidth,			/* Width */
			   1				/* Height (here: one line) */
	    )
	)
	{
	    D(bug("bmp.datatype/LoadBMP() --- WRITEPIXELARRAY failed !\n"));
	    BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	    return FALSE;
	}
    }
    //D(bug("bmp.datatype/LoadBMP() --- bytes of %ld (%ld) bytes\n", (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));

    D(bug("bmp.datatype/LoadBMP() --- Normal Exit\n"));
    BMP_Exit(bmphandle, 0);
    return TRUE;
}

/**************************************************************************************************/

static BOOL SaveBMP(struct IClass *cl, Object *o, struct dtWrite *dtw )
{
    BmpHandleType           *bmphandle;
    UBYTE                   *filebuf;
    unsigned int            width, height, widthxheight, numplanes, numcolors;
    struct BitMapHeader     *bmhd;
    struct BitMap           *bm;
    struct RastPort         rp;
    long                    *colorregs;
    int                     i, j, ret;

    D(bug("bmp.datatype/SaveBMP()\n"));

    if( !(bmphandle = AllocMem(sizeof(BmpHandleType), MEMF_ANY)) )
    {
	SetIoErr(ERROR_NO_FREE_STORE);
	return FALSE;
    }
    bmphandle->filebuf = NULL;
    bmphandle->linebuf = NULL;
    bmphandle->codecvars = NULL;

    /* A NULL file handle is a NOP */
    if( !dtw->dtw_FileHandle )
    {
	D(bug("bmp.datatype/SaveBMP() --- empty Filehandle - just testing\n"));
	BMP_Exit(bmphandle, 0);
	return TRUE;
    }
    bmphandle->filehandle = dtw->dtw_FileHandle;

    /* Get BitMap and color palette */
    if( GetDTAttrs( o,  PDTA_BitMapHeader, (IPTR)&bmhd,
			PDTA_BitMap,       (IPTR)&bm,
			PDTA_CRegs,        (IPTR)&colorregs,
			PDTA_NumColors,    (IPTR)&numcolors,
			TAG_DONE ) != 4UL ||
	!bmhd || !bm || !colorregs || !numcolors)
    {
	D(bug("bmp.datatype/SaveBMP() --- missing attributes\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_NOT_FOUND);
	return FALSE;
    }
#if 0
    /* Check if this is a standard BitMap */
    if( !( GetBitMapAttr(bm, BMA_FLAGS) & BMF_STANDARD ) )
    {
	D(bug("bmp.datatype/SaveBMP() --- wrong BitMap type\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
#endif
    /* initialize buffered file reads */
    bmphandle->filebufsize = FILEBUFSIZE;
    bmphandle->filebufbytes = bmphandle->filebufsize;
    if( !(bmphandle->filebuf = bmphandle->filebufpos = AllocMem(bmphandle->filebufsize, MEMF_ANY)) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }

    /* write BMP 87a header to file, make sure, there are at least 13 bytes in buffer */
    if ( (bmphandle->filebufbytes -= 13) < 0 && !SaveBMP_EmptyBuf(bmphandle, 13) )
    {
	D(bug("bmp.datatype/SaveBMP() --- filling buffer with header failed\n"));
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }
    filebuf = bmphandle->filebufpos;    /* this makes things easier */
    bmphandle->filebufpos += 13;

    /* set screen descriptor attributes (from BitMapHeader) */
    width = bmhd->bmh_PageWidth;
    height = bmhd->bmh_PageHeight;
    numplanes = bmhd->bmh_Depth - 1;
    numcolors = 1 << (numplanes + 1);
    D(bug("bmp.datatype/SaveBMP() --- BMP-Image %d x %d x %d, cols %d\n", width, height, numplanes+1, numcolors));
    filebuf[6] = width & 0xff;
    filebuf[7] = width >> 8;
    filebuf[8] = height & 0xff;
    filebuf[9] = height >> 8;
    filebuf[10] = 0x80 | ((numplanes & 0x07) << 4) | (numplanes & 0x07) ; /* set numplanes, havecolmap=1 */
    filebuf[11] = 0;    /* this is fillcolor */
    filebuf[12] = 0;    /* this is pixel aspect ratio, 0 means unused */

    /* write screen colormap, we don't use an image colormap */
    for (i = 0; i < numcolors*3; i += 3)
    {
	if ( (bmphandle->filebufbytes -= 3) < 0 && !SaveBMP_EmptyBuf(bmphandle, 3) )
	{
	    BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	    return FALSE;
	}
	*(bmphandle->filebufpos)++ = colorregs[i] >> 24;
	*(bmphandle->filebufpos)++ = colorregs[i+1] >> 24;
	*(bmphandle->filebufpos)++ = colorregs[i+2] >> 24;
    }

    /* write image header, image has same size as screen */
    if ( (bmphandle->filebufbytes -= 10) < 0 && !SaveBMP_EmptyBuf(bmphandle, 10) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }
    filebuf = bmphandle->filebufpos;    /* this makes things easier */
    bmphandle->filebufpos += 10;
    filebuf[0] = ',';       /* header ID */
    filebuf[1] = filebuf[2] = 0;    /* no left edge */
    filebuf[3] = filebuf[4] = 0;    /* no top edge */
    filebuf[5] = width & 0xff;
    filebuf[6] = width >> 8;
    filebuf[7] = height & 0xff;
    filebuf[8] = height >> 8;
    filebuf[9] = numplanes & 0x07; /* set numplanes, havecolmap=0, interlaced=0 */

    /* Now read the picture data from the bitplanes and write it to a chunky buffer */
    /* For now, we use a full picture pixel buffer, not a single line */
    widthxheight = width*height;
    bmphandle->linebufsize = bmphandle->linebufbytes = widthxheight;
    if (! (bmphandle->linebuf = bmphandle->linebufpos = AllocMem(bmphandle->linebufsize, MEMF_ANY)) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }
    InitRastPort(&rp);
    rp.BitMap=bm;
    for (j=0; j<height; j++)
    {
	for (i=0; i<width; i++)
	{
	    ret = (UBYTE)ReadPixel(&rp, i, j);  /* very slow, to be changed */
	    *(bmphandle->linebufpos)++ = ret;
	}
    }
    bmphandle->linebufpos = bmphandle->linebuf;

    /* write the chunky buffer to file, after encoding */
    
    /* write end-of-BMP marker */
    if ( !bmphandle->filebufbytes-- && !SaveBMP_EmptyBuf(bmphandle, 1) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }
    *(bmphandle->filebufpos)++ = ';';

    /* flush write buffer to file and exit */
    SaveBMP_EmptyBuf(bmphandle, 0);
    D(bug("bmp.datatype/SaveBMP() --- Normal Exit\n"));
    BMP_Exit(bmphandle, 0);
    return TRUE;
}

/**************************************************************************************************/

IPTR BMP__OM_NEW(Class *cl, Object *o, Msg msg)
{
    Object *newobj;
    
    D(bug("bmp.datatype/DT_Dispatcher: Method OM_NEW\n"));
    
    newobj = (Object *)DoSuperMethodA(cl, o, msg);
    if (newobj)
    {
	if (!LoadBMP(cl, newobj))
	{
	    CoerceMethod(cl, newobj, OM_DISPOSE);
	    newobj = NULL;
	}
    }

    return (IPTR)newobj;
}

/**************************************************************************************************/

IPTR BMP__DTM_WRITE(Class *cl, Object *o, struct dtWrite *dtw)
{
    D(bug("bmp.datatype/DT_Dispatcher: Method DTM_WRITE\n"));
    if( (dtw -> dtw_Mode) == DTWM_RAW )
    {
	/* Local data format requested */
	return SaveBMP(cl, o, dtw );
    }
    else
    {
	/* Pass msg to superclass (which writes an IFF ILBM picture)... */
	return DoSuperMethodA( cl, o, (Msg)dtw );
    }
}
/*
    Copyright © 1995-2001, The AROS Development Team. All rights reserved.
    $Id: ppmclass.c 30902 2009-03-14 13:38:20Z mazze $
*/

/**********************************************************************/

#define DEBUGMETHODS 0

/**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dostags.h>
#include <graphics/gfxbase.h>
#include <graphics/rpattr.h>
#include <intuition/imageclass.h>
#include <intuition/icclass.h>
#include <intuition/gadgetclass.h>
#include <intuition/cghooks.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>

#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/iffparse.h>
#include <proto/datatypes.h>

#include <aros/symbolsets.h>

ADD2LIBS("datatypes/picture.datatype", 0, struct Library *, PictureBase);

#include "debug.h"

#include "methods.h"

/**************************************************************************************************/

IPTR PPM__OM_NEW(Class *cl, Object *o, struct opSet *msg)
{
 IPTR RetVal;
 char *Title;
 IPTR sourcetype;
 BPTR FileHandle;
 struct BitMapHeader *bmhd;
 char LineBuffer[128];
 long Width, Height, NumChars;
 unsigned int i;
 unsigned char *RGBBuffer;

 D(bug("ppm.datatype/OM_NEW: Entering\n"));

 D(bug("ppm.datatype/OM_NEW: cl: 0x%lx o: 0x%lx msg: 0x%lx\n", (unsigned long) cl, (unsigned long) o, (unsigned long) msg));

 RetVal=DoSuperMethodA(cl, o, (Msg) msg);
 if(!RetVal)
 {
  D(bug("ppm.datatype/OM_NEW: DoSuperMethod failed\n"));
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: DoSuperMethod: 0x%lx\n", (unsigned long) RetVal));

    if( GetDTAttrs((Object *) RetVal,
			DTA_SourceType    , (IPTR)&sourcetype ,
			DTA_Handle        , (IPTR)&FileHandle,
			DTA_Name          , (IPTR)&Title,
			PDTA_BitMapHeader , (IPTR)&bmhd,
			TAG_DONE) != 4 )
    {
        D(bug("ppm.datatype/OM_NEW: GetDTAttrs(DTA_Handle, DTA_BitMapHeader) error !\n"));
	CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
	SetIoErr(ERROR_OBJECT_NOT_FOUND);
	return FALSE;
    }
    D(bug("ppm.datatype/OM_NEW: GetDTAttrs(DTA_Handle, DTA_BitMapHeader) successful\n"));
    
    if ( sourcetype == DTST_RAM && FileHandle == NULL )
    {
	D(bug("ppm.datatype/OM_NEW: Creating an empty object\n"));
	return TRUE;
    }
    if ( sourcetype != DTST_FILE || !FileHandle || !bmhd )
    {
	D(bug("ppm.datatype/OM_NEW: Unsupported sourcetype mode\n"));
	SetIoErr(ERROR_NOT_IMPLEMENTED);
	return FALSE;
    }

 D(bug("ppm.datatype/OM_NEW: Title: %s\n", Title?Title:"[none]"));

 Seek(FileHandle, 0, OFFSET_BEGINNING);
 D(bug("ppm.datatype/OM_NEW: Seek successful\n"));

 if(!FGets(FileHandle, LineBuffer, 128))
 {
  D(bug("ppm.datatype/OM_NEW: FGets line 1 failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 if(!(LineBuffer[0]=='P' && LineBuffer[1]=='6'))
 {
  D(bug("ppm.datatype/OM_NEW: Not a P6 PPM\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: It's a P6 PPM\n"));

 if(!FGets(FileHandle, LineBuffer, 128))
 {
  D(bug("ppm.datatype/OM_NEW: FGets line 2 failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 if(LineBuffer[0]=='#')
 {
  D(bug("ppm.datatype/OM_NEW: Line 2 is a comment\n"));

  if(!FGets(FileHandle, LineBuffer, 128))
  {
   D(bug("ppm.datatype/OM_NEW: FGets line 3 after comment failed\n"));

   SetIoErr(ERROR_OBJECT_WRONG_TYPE);
   CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
   return(0);
  }
 }

 NumChars=StrToLong(LineBuffer, (LONG *)&Width);

 if(!((NumChars>0) && (Width>0)))
 {
  D(bug("ppm.datatype/OM_NEW: StrToLong(Width) failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: Width: %ld\n", (long) Width));
 D(bug("ppm.datatype/OM_NEW: NumChars: %ld\n", (long) NumChars));

 NumChars=StrToLong(LineBuffer+NumChars, (LONG *)&Height);

 if(!((NumChars>0) && (Height>0)))
 {
  D(bug("ppm.datatype/OM_NEW: StrToLong(Height) failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: Height: %ld\n", (long) Height));
 D(bug("ppm.datatype/OM_NEW: NumChars: %ld\n", (long) NumChars));

 if(!FGets(FileHandle, LineBuffer, 128))
 {
  D(bug("ppm.datatype/OM_NEW: FGets line 3 (4) failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 if(!(LineBuffer[0]=='2' && LineBuffer[1]=='5' && LineBuffer[2]=='5'))
 {
  D(bug("ppm.datatype/OM_NEW: Wrong depth\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: Header successful read\n"));

 bmhd->bmh_Width  = Width;
 bmhd->bmh_Height = Height;
 bmhd->bmh_PageWidth = bmhd->bmh_Width;
 bmhd->bmh_PageHeight = bmhd->bmh_Height;

 D(bug("ppm.datatype/OM_NEW: Using 24 bit colors\n"));
 bmhd->bmh_Depth = 24;

 /* Get a buffer for one line of RGB triples */
 RGBBuffer=AllocVec(Width*3, MEMF_ANY | MEMF_CLEAR);
 if(!RGBBuffer)
 {
  D(bug("ppm.datatype/OM_NEW: AllocVec(RGBBuffer) failed\n"));
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  SetIoErr(ERROR_NO_FREE_STORE);
  return(0);
 }
 D(bug("ppm.datatype/OM_NEW: RGBBuffer successfully allocated\n"));

 /* Flush filehandle, so that unbuffered Read() can be used after buffered FGets() */
 Flush(FileHandle);

 /* Copy picture line by line to picture.datatype using WRITEPIXELARRAY method */
 for(i=0; i<Height; i++)
 {
  if(!(Read(FileHandle, RGBBuffer, (Width*3))==(Width*3)))
  {
   D(bug("ppm.datatype/OM_NEW: Read(RGBBuffer) failed, maybe file too short\n"));
   FreeVec(RGBBuffer);
   CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
   SetIoErr(ERROR_OBJECT_WRONG_TYPE);
   return(0);
  }
  if(!DoSuperMethod(cl, (Object *) RetVal,
		PDTM_WRITEPIXELARRAY,	/* Method_ID */
		(IPTR) RGBBuffer,	/* PixelData */
		PBPAFMT_RGB,		/* PixelFormat */
		Width*3,		/* PixelArrayMod (number of bytes per row) */
		0,			/* Left edge */
		i,			/* Top edge */
		Width,			/* Width */
		1))			/* Height (here: one line) */
   {
	D(bug("ppm.datatype/OM_NEW: WRITEPIXELARRAY failed\n"));
	FreeVec(RGBBuffer);
	CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
	return(0);
   }
 }
 D(bug("ppm.datatype/OM_NEW: WRITEPIXELARRAY of whole picture done\n"));

 FreeVec(RGBBuffer);

 SetDTAttrs((Object *) RetVal, NULL, NULL, DTA_ObjName,      (IPTR) Title,
					   DTA_NominalHoriz, Width,
					   DTA_NominalVert,  Height,
					   TAG_DONE);

 D(bug("ppm.datatype/OM_NEW: Leaving. (24 bit mode)\n"));
 return(RetVal);
} /* PPM_New() */

/**************************************************************************************************/

static BOOL PPM_Save(struct IClass *cl, Object *o, struct dtWrite *dtw )
{
    BPTR		    filehandle;
    unsigned int            width, height, numplanes, y;
    UBYTE		    *linebuf;
    struct BitMapHeader     *bmhd;
    long                    *colorregs;

    D(bug("ppm.datatype/PPM_Save()\n"));

    /* A NULL file handle is a NOP */
    if( !dtw->dtw_FileHandle )
    {
	D(bug("ppm.datatype/PPM_Save() --- empty Filehandle - just testing\n"));
	return TRUE;
    }
    filehandle = dtw->dtw_FileHandle;

    /* Get BitMapHeader and color palette */
    if( GetDTAttrs( o,  PDTA_BitMapHeader, (IPTR) &bmhd,
			PDTA_CRegs,        (IPTR) &colorregs,
			TAG_DONE ) != 2UL ||
	!bmhd || !colorregs )
    {
	D(bug("ppm.datatype/PPM_Save() --- missing attributes\n"));
	SetIoErr(ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }

    width = bmhd->bmh_Width;
    height = bmhd->bmh_Height;
    numplanes = bmhd->bmh_Depth;
    if( numplanes != 24 )
    {
	D(bug("ppm.datatype/PPM_Save() --- color depth %d, can save only depths of 24\n", numplanes));
	SetIoErr(ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    D(bug("ppm.datatype/PPM_Save() --- Picture size %d x %d (x %d bit)\n", width, height, numplanes));

    /* Write header to file */
    if( FPrintf( filehandle, "P6\n#Created by AROS ppm.datatype aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n%ld %ld\n255\n",
	(long)width, (long)height ) == -1 )
    {
	D(bug("ppm.datatype/PPM_Save() --- writing header failed\n"));
	return FALSE;
    }

    /* Now read the picture data line by line and write it to a chunky buffer */
    if( !(linebuf = AllocVec(width*3, MEMF_ANY)) )
    {
	SetIoErr(ERROR_NO_FREE_STORE);
	return FALSE;
    }
    D(bug("ppm.datatype/PPM_Save() --- copying picture with READPIXELARRAY\n"));
    for (y=0; y<height; y++)
    {
	if(!DoSuperMethod(cl, o,
			PDTM_READPIXELARRAY,	/* Method_ID */
			(IPTR)linebuf,		/* PixelData */
			PBPAFMT_RGB,		/* PixelFormat */
			width,			/* PixelArrayMod (number of bytes per row) */
			0,			/* Left edge */
			y,			/* Top edge */
			width,			/* Width */
			1))			/* Height */
	{
	    D(bug("ppm.datatype/PPM_Save() --- READPIXELARRAY line %d failed !\n", y));
	    FreeVec(linebuf);
	    SetIoErr(ERROR_OBJECT_WRONG_TYPE);
	    return FALSE;
	}
	if( FWrite( filehandle, linebuf, width*3, 1 ) != 1 )
	{
	    D(bug("ppm.datatype/PPM_Save() --- writing picture data line %d failed !\n", y));
	    FreeVec(linebuf);
	    return FALSE;
	}
    }

    D(bug("ppm.datatype/PPM_Save() --- Normal Exit\n"));
    FreeVec(linebuf);
    SetIoErr(0);
    return TRUE;
}

/**************************************************************************************************/

IPTR PPM__DTM_WRITE(struct IClass *cl, Object *o, struct dtWrite *dtw)
{
    if( (dtw -> dtw_Mode) == DTWM_RAW )
    {
	/* Local data format requested */
	return PPM_Save(cl, o, dtw );
    }
    else
    {
	/* Pass msg to superclass (which writes an IFF ILBM picture)... */
	return DoSuperMethodA( cl, o, (Msg)dtw );
    }
}

/**************************************************************************************************/

#if DEBUGMETHODS

STATIC IPTR DT_NotifyMethod(struct IClass *cl, struct Gadget *g, struct opUpdate *msg)
{
 return(DoSuperMethodA(cl, (Object *) g, (Msg) msg));
}

/**************************************************************************************************/
STATIC IPTR DT_SetMethod(struct IClass *cl, struct Gadget *g, struct opSet *msg)
{
 IPTR RetVal;

 D(bug("ppm.datatype/OM_SET: Entering\n"));

 RetVal=DoSuperMethodA(cl, (Object *) g, (Msg) msg);

 return(RetVal);
}

/**************************************************************************************************/
STATIC IPTR DT_GetMethod(struct IClass *cl, struct Gadget *g, struct opGet *msg)
{
 IPTR RetVal;

 D(bug("ppm.datatype/OM_GET: Entering\n"));

 RetVal=DoSuperMethodA(cl, (Object *) g, (Msg) msg);

 return(RetVal);
}

/**************************************************************************************************/

STATIC IPTR DT_LayoutMethod(struct IClass *cl, struct Gadget *g, struct gpLayout *msg)
{
 IPTR RetVal;
 const char L[]="GM_LAYOUT";
 const char P[]="DTM_PROCLAYOUT";
 const char A[]="DTM_ASYNCLAYOUT";
 const char U[]="Unknown Method";
 char *MethodName;

 RetVal=DoSuperMethodA(cl, (Object *) g, (Msg) msg);

 D(bug("ppm.datatype/%s: RetVal 0x%lx\n", MethodName, (unsigned int) RetVal));

 D(bug("ppm.datatype/%s: Leaving\n", MethodName));

 return(RetVal);
}

#endif /* DEBUGMETHODS */

Creating New Datatypes

IPTR DTD__OM_NEW(Class *cl, Object *o, struct opSet *msg)
{

} /* DTD_OM_New() */

/**************************************************************************************************/

static BOOL DTD_Load(struct IClass *cl, Object *o)
{

}

static BOOL DTD_Save(struct IClass *cl, Object *o, struct dtWrite *dtw )
{

}

IPTR DTD__DTM_WRITE(struct IClass *cl, Object *o, struct dtWrite *dtw)
{

}

/**************************************************************************************************/

STATIC IPTR DT_SetMethod(struct IClass *cl, struct Gadget *g, struct opSet *msg)
{

}

STATIC IPTR DT_GetMethod(struct IClass *cl, struct Gadget *g, struct opGet *msg)
{

}

STATIC IPTR DT_LayoutMethod(struct IClass *cl, struct Gadget *g, struct gpLayout *msg)
{

}

init

/* Programmheader

	Name:		init.c
	Main:		reko
	Versionstring:	$VER: init.c 1.1 (18.10.1999)
	Author:		SDI
	Distribution:	Freeware
	Description:	all the datatype initialization stuff

 1.0   19.09.99 : first version
 1.1   18.10.99 : fixed the stuff a bit
*/

#include <proto/exec.h>
#include <proto/intuition.h>
#include <dos/dos.h>
#include <exec/resident.h>
#include <exec/initializers.h>
#include <exec/execbase.h>
#include "SDI_compiler.h"

#include "reko.h"

struct LibInitData {
 UBYTE i_Type;     UBYTE o_Type;     UBYTE  d_Type;	UBYTE p_Type;
 UBYTE i_Name;     UBYTE o_Name;     STRPTR d_Name;
 UBYTE i_Flags;    UBYTE o_Flags;    UBYTE  d_Flags;	UBYTE p_Flags;
 UBYTE i_Version;  UBYTE o_Version;  UWORD  d_Version;
 UBYTE i_Revision; UBYTE o_Revision; UWORD  d_Revision;
 UBYTE i_IdString; UBYTE o_IdString; STRPTR d_IdString;
 ULONG endmark;
};

/************************************************************************/

/* First executable routine of this library; must return an error
   to the unsuspecting caller */
LONG ReturnError(void)
{
  return -1;
}

/************************************************************************/

/* The mandatory reserved library function */
ULONG LibReserved(void)
{
  return 0;
}

/************************************************************************/

ASM(struct Library *) LibInit(REG(d0, struct ClassBase *cb), REG(a0, BPTR seglist), REG(a6, struct ExecBase * SysBase))
{
#ifdef _M68060
  if(!(SysBase->AttnFlags & AFF_68060))
    return 0;
#elif defined (_M68040)
  if(!(SysBase->AttnFlags & AFF_68040))
    return 0;
#elif defined (_M68030)
  if(!(SysBase->AttnFlags & AFF_68030))
    return 0;
#elif defined (_M68020)
  if(!(SysBase->AttnFlags & AFF_68020))
    return 0;
#endif
  InitSemaphore(&cb->cb_Lock);

  cb->cb_SegList = seglist;
  cb->cb_SysBase = SysBase;
  if((cb->cb_IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",39)))
  {
    if((cb->cb_GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 39)))
    {
      if((cb->cb_DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 39)))
      {
	if((cb->cb_UtilityBase = (struct UtilityBase *) OpenLibrary ("utility.library", 39)))
	  return (struct Library *) cb;

	CloseLibrary((struct Library *) cb->cb_DOSBase);
      }
      CloseLibrary((struct Library *) cb->cb_GfxBase);
    }
    CloseLibrary((struct Library *) cb->cb_IntuitionBase);
  }

  FreeMem((STRPTR) cb - cb->cb_Lib.lib_NegSize, cb->cb_Lib.lib_NegSize + cb->cb_Lib.lib_PosSize);
  return 0;
}

ASM(struct ClassBase *) LibOpen(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;
  struct ClassBase *ret = cb;

  ObtainSemaphore(&cb->cb_Lock);

  cb->cb_Lib.lib_Flags &= ~LIBF_DELEXP;
  cb->cb_Lib.lib_OpenCnt++;

  if(!cb->cb_Class)
  {
    if((cb->cb_DataTypesBase = OpenLibrary ("datatypes.library", 39)))
    {
      if((cb->cb_SuperClassBase = OpenLibrary ("datatypes/picture.datatype", 39)))
      {
	if((cb->cb_Class = initClass(cb)))
	{
          ReleaseSemaphore(&cb->cb_Lock);
          return ret;
	}
	CloseLibrary(cb->cb_SuperClassBase);
      }
      CloseLibrary(cb->cb_DataTypesBase);
    }
    cb->cb_Lib.lib_OpenCnt--;
    ret = 0;
  }

  ReleaseSemaphore(&cb->cb_Lock);
  return ret;
}

ASM(LONG) LibExpunge(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;

  if(!cb->cb_Lib.lib_OpenCnt)
  {
    if(cb->cb_Class) /* security, should never happen */
    {
      struct IntuitionBase *IntuitionBase = cb->cb_IntuitionBase;
      if(FreeClass(cb->cb_Class))
      {
        cb->cb_Class = 0;
        CloseLibrary(cb->cb_SuperClassBase);
        CloseLibrary(cb->cb_DataTypesBase);
      }
    }
    if(!cb->cb_Class)
    {
      BPTR seg = cb->cb_SegList;

      Remove((struct Node *) cb);
      CloseLibrary((struct Library *) cb->cb_UtilityBase);
      CloseLibrary((struct Library *) cb->cb_DOSBase);
      CloseLibrary((struct Library *) cb->cb_GfxBase);
      CloseLibrary((struct Library *) cb->cb_IntuitionBase);

      FreeMem((STRPTR) cb - cb->cb_Lib.lib_NegSize, cb->cb_Lib.lib_NegSize + cb->cb_Lib.lib_PosSize);

      return seg;
    }
  }
  cb->cb_Lib.lib_Flags |= LIBF_DELEXP;
  return 0;
}

ASM(LONG) LibClose(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;

  ObtainSemaphore(&cb->cb_Lock);

  if(cb->cb_Lib.lib_OpenCnt)
    cb->cb_Lib.lib_OpenCnt--;

  if(!cb->cb_Lib.lib_OpenCnt && cb->cb_Class)
  {
    struct IntuitionBase *IntuitionBase = cb->cb_IntuitionBase;
    if(FreeClass(cb->cb_Class))
    {
      cb->cb_Class = 0;
      CloseLibrary(cb->cb_SuperClassBase);
      CloseLibrary(cb->cb_DataTypesBase);
    }
  }

  ReleaseSemaphore(&cb->cb_Lock);
  /* A bit dangerous, but we cannot release a semaphore after expunging! */
  return (cb->cb_Lib.lib_Flags & LIBF_DELEXP) ? LibExpunge(cb) : 0;
}

/************************************************************************/

ASM(Class *) ObtainEngine(REG(a6, struct ClassBase *cb))
{
  return cb->cb_Class;
}

/************************************************************************/

/* This is the table of functions that make up the library. The first
   four are mandatory, everything following it are user callable
   routines. The table is terminated by the value -1. */

static const APTR LibVectors[] = {
  LibOpen,
  LibClose,
  LibExpunge,
  LibReserved,
  ObtainEngine,
  (APTR)-1
};

static const struct LibInitData LibInitData = {
 0xA0, (UBYTE) OFFSET(Node,    ln_Type),      NT_LIBRARY,		 0,
 0x80, (UBYTE) OFFSET(Node,    ln_Name),      CLASSNAME,
 0xA0, (UBYTE) OFFSET(Library, lib_Flags),    LIBF_SUMUSED|LIBF_CHANGED, 0,
 0x90, (UBYTE) OFFSET(Library, lib_Version),  VERSION,
 0x90, (UBYTE) OFFSET(Library, lib_Revision), REVISION,
 0x80, (UBYTE) OFFSET(Library, lib_IdString), IDSTRING,
 0
};

/* The following data structures and data are responsible for
   setting up the Library base data structure and the library
   function vector. */

static const ULONG LibInitTable[4] = {
  (ULONG)sizeof(struct ClassBase), /* Size of the base data structure */
  (ULONG)LibVectors,             /* Points to the function vector */
  (ULONG)&LibInitData,           /* Library base data structure setup table */
  (ULONG)LibInit                 /* The address of the routine to do the setup */
};

/************************************************************************/

/* The library loader looks for this marker in the memory
   the library code and data will occupy. It is responsible
   setting up the Library base data structure.
*/

static const struct Resident RomTag = {
  RTC_MATCHWORD,                /* Marker value. */
  (struct Resident *)&RomTag,   /* This points back to itself. */
  (struct Resident *)&RomTag+1, /* This points behind this marker. */
  RTF_AUTOINIT,                 /* The Library should be set up according to the given table. */
  VERSION,                      /* The version of this Library. */
  NT_LIBRARY,                   /* This defines this module as a Library. */
  0,                            /* Initialization priority of this Library; unused. */
  CLASSNAME,                    /* Points to the name of the Library. */
  IDSTRING,                     /* The identification string of this Library. */
  (APTR)&LibInitTable           /* This table is for initializing the Library. */
};

Dispatcher

/* Programmheader

	Name:		dispatch.c
	Main:		reko
	Versionstring:	$VER: dispatch.c 1.11 (13.07.2003)
	Author:		SDI
	Distribution:	Freeware
	Description:	the real stuff

 1.0   19.09.99 : first version
 1.1   02.10.99 : added PC stuff
 1.2   03.10.99 : some optimizations
 1.3   10.10.99 : added HAM conversion
 1.4   14.10.99 : added ENV variable support
 1.5   17.10.99 : now passes ModeID in HighColor system
 1.6   20.10.99 : added HAM6 mode and card clear
 1.7   11.11.99 : Now the data is told to be 24 bit!
 1.8   10.12.99 : added 16BIT/24BIT keywords
 1.9   04.11.01 : added support for layout of older reko datatypes
 1.10  18.12.01 : fixed Preview for RKP8 and RKP16
 1.11  13.07.03 : added WizSolitaire cardset type
*/

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/datatypes.h>
#include <proto/utility.h>
#include <clib/alib_protos.h>
#include <datatypes/pictureclass.h>
#include <libraries/iffparse.h>
#include <exec/memory.h>
#include <datatypes/pictureclass.h>

#include "SDI_compiler.h"
#include "reko.h"

#define DOSBase		cb->cb_DOSBase
#define SysBase		cb->cb_SysBase
#define DataTypesBase	cb->cb_DataTypesBase
#define UtilityBase	cb->cb_UtilityBase
#define GfxBase		cb->cb_GfxBase
#define IntuitionBase	cb->cb_IntuitionBase

#define REKOFLAG_SOLITON	(1<<0)
#define REKOFLAG_PREVIEW	(1<<1)
#define REKOFLAG_HAMDIRECT	(1<<2)
#define REKOFLAG_16BIT		(1<<3)
#define REKOFLAG_REKODT39	(1<<4)
#define REKOFLAG_MREKO		(1<<5)

#define REKOFLAG_PCMODE		(1<<6)
#define REKOFLAG_WIZMODE	(1<<7)

struct RekoHeader /* REKO file header */
{
  ULONG rh_ID;
  ULONG rh_BodySize;
  ULONG rh_CardSize;
  UWORD rh_Height;
  UWORD rh_Width;
  ULONG rh_ModeID;
  UBYTE rh_Depth;
  UBYTE rh_CardsCnt;
};

struct PCRekoHeader /* PCREKO file header */
{ /* all in INTEL format */
  UWORD rh_PCID;
  ULONG rh_ID;
  UWORD rh_ID2;
  ULONG rh_BodySize; /* FileSize-22 */
  ULONG rh_CardSize;
  UWORD rh_Width;
  UWORD rh_Height;
  UBYTE rh_Depth;
  UBYTE rh_CardsCnt;
};

struct WizData
{
  ULONG Unknown;
  ULONG Width;
  ULONG Height;
  UBYTE Order; /* 1 to 13 */
  UBYTE Color; /* 0 to 3 */
  ULONG JPEGSize;
};

struct WizHeader
{
  UBYTE ID[16];
  UBYTE Empty[4];
  /* We read 2 bytes too much, as reko header has 2 more bytes */
};

#define ID_REKO			MAKE_ID('R','E','K','O')
#define ID_PC			0x5043
#define ID_WIZ			0x57697A53

#define HEADER_SIZE		sizeof(struct RekoHeader)
#define WIZDATA_SIZE		sizeof(struct WizData)

#define FULLHEIGHT		4  /* Number of cards vertically */
#define NORMWIDTH		14
#define FULLWIDTH               17
#define REKO_I			55 /* Cards in REKO I cardset */
#define REKO_II			59 /* Cards in REKO II cardset */
#define REKO_III		68 /* Cards in REKO III cardset */

#define BORDERCOL	0xF0
#define BACKCOL		0

static const UBYTE Mapping[REKO_III][2] = {
  {13,2}, {13,1}, {13,0},
  { 0,0}, { 0,1}, { 0,2}, { 0,3},
  { 1,0}, { 1,1}, { 1,2}, { 1,3},
  { 2,0}, { 2,1}, { 2,2}, { 2,3},
  { 3,0}, { 3,1}, { 3,2}, { 3,3},
  { 4,0}, { 4,1}, { 4,2}, { 4,3},
  { 5,0}, { 5,1}, { 5,2}, { 5,3},
  { 6,0}, { 6,1}, { 6,2}, { 6,3},
  { 7,0}, { 7,1}, { 7,2}, { 7,3},
  { 8,0}, { 8,1}, { 8,2}, { 8,3},
  { 9,0}, { 9,1}, { 9,2}, { 9,3},
  {10,0}, {10,1}, {10,2}, {10,3},
  {11,0}, {11,1}, {11,2}, {11,3},
  {12,0}, {12,1}, {12,2}, {12,3},
  {13,3}, {14,3}, {15,3}, {16,3},
  {14,0}, {15,0}, {16,0},
  {14,1}, {15,1}, {16,1},
  {14,2}, {15,2}, {16,2}
};

static const UBYTE WizMapping[REKO_III][2] = {
  {13,0},
  { 0,0}, { 1,0}, { 2,0}, { 3,0}, { 4,0}, { 5,0}, { 6,0}, { 7,0}, { 8,0}, { 9,0}, {10,0}, {11,0}, {12,0},
  { 0,1}, { 1,1}, { 2,1}, { 3,1}, { 4,1}, { 5,1}, { 6,1}, { 7,1}, { 8,1}, { 9,1}, {10,1}, {11,1}, {12,1},
  { 0,2}, { 1,2}, { 2,2}, { 3,2}, { 4,2}, { 5,2}, { 6,2}, { 7,2}, { 8,2}, { 9,2}, {10,2}, {11,2}, {12,2},
  { 0,3}, { 1,3}, { 2,3}, { 3,3}, { 4,3}, { 5,3}, { 6,3}, { 7,3}, { 8,3}, { 9,3}, {10,3}, {11,3}, {12,3},
  {13,3}, {14,3}, {15,3}, {16,3},
  {13,1}, /* empty card */
  {13,2}, {14,0}, {14,1}, {14,2}, {15,0}, {15,1}, {15,2}, {16,0}, {16,1}, {16,2}
};

ASM(Object *) Dispatch(REG(a0, Class *cl), REG(a2, Object *o), REG(a1, Msg msg));

Class *initClass(struct ClassBase *cb)
{
  Class *CL;

  /* Create our class (no instance) */
  if((CL=MakeClass(CLASSNAME,PICTUREDTCLASS,NULL,NULL,0)))
  {
    CL->cl_Dispatcher.h_Entry=(HOOKFUNC)Dispatch;
    CL->cl_UserData=(ULONG) cb;
    AddClass(CL);
  }
  return CL;
}

/* Calculate number of cards horizontally */
static ULONG GetFullWidth(ULONG cards)
{
  ULONG HCnt;

  if(cards <= REKO_I) /* REKO-I cardset */
    HCnt=NORMWIDTH;
  else if(cards <= REKO_III) /* REKO-II or REKO-III cardset */
    HCnt=FULLWIDTH;
  else /* Unknown cardset */
    HCnt=cards/FULLHEIGHT+(cards%FULLHEIGHT>0);
  return HCnt;
}

ASM(static void) putfunc(REG(d0, UBYTE data), REG(a3, STRPTR *a))
{
  *((*a)++) = data;
}

static void SPrintF(struct ClassBase *cb, STRPTR buf, STRPTR format, ...)
{
  STRPTR buf2 = buf;

  RawDoFmt(format, (APTR) ((ULONG)&format+sizeof(STRPTR)),
  (void(*)()) putfunc, &buf2);
}

static void MakeBackCard(STRPTR buf, ULONG width, ULONG height)
{
  ULONG j;
  STRPTR b;

  b = buf;
  for(j = width*height*3; j; --j) /* clear background */
    *(b++) = BACKCOL;

  b = buf+3;
  for(j = (width-2)*3; j; --j) /* upper border */
    *(b++) = BORDERCOL;

  b = buf+((width*(height-1))+1)*3;
  for(j = (width-2)*3; j; --j) /* bottom border */
    *(b++) = BORDERCOL;

  b = buf + width*3;
  for(j = height-2; j ; --j) /* side borders */
  {
    b[0] = b[1] = b[2] = BORDERCOL;
    b += width*3;
    *(b-3) = *(b-2) = *(b-1) = BORDERCOL;
  }
  
  b = buf + width*3;
  b[3] = b[4] = b[5] = BORDERCOL;
  b += width*3;
  *(b-6) = *(b-5) = *(b-4) = BORDERCOL;
  b = buf + width*(height-2)*3;
  b[3] = b[4] = b[5] = BORDERCOL;
  b += width*3;
  *(b-6) = *(b-5) = *(b-4) = BORDERCOL;
}

static void GetXY(ULONG num, ULONG *x, ULONG *y, ULONG flags)
{
  if(flags & REKOFLAG_PREVIEW)
  {
    *x = *y = 0;
  }
  else if(flags & REKOFLAG_WIZMODE)
  {
    *x = WizMapping[num][0];
    *y = WizMapping[num][1];
  }
  else if(num < REKO_III)
  {
    *x = Mapping[num][0];
    *y = Mapping[num][1];
    if(num < 3)
    {
      if(flags & REKOFLAG_MREKO)
      {
        switch(num)
        {
        case 0: *y = 1; break;
        case 1: *y = 2; break;
        case 2: *y = 3; break;
        };
      }
      else if(flags & REKOFLAG_REKODT39)
      {
        *y = 1;
        switch(num)
        {
        case 0: *x = 13; break;
        case 1: *x = 14; break;
        case 2: *x = 15; break;
        }
      }
    }
    else if(num >= REKO_I && (flags & (REKOFLAG_MREKO|REKOFLAG_REKODT39)))
    {
      if(num < REKO_II) /* stack cards */
        *y = 0;
      else if((flags & REKOFLAG_REKODT39) && num < REKO_II+2)
      {
        *x = 13; *y = num-REKO_II+2;
      }
      else
        (*y)++;
    }
  }
  else
  {
    *x = num/FULLHEIGHT;
    *y = num%FULLHEIGHT;
  }
}

static void ClearCards(ULONG cnt, struct ClassBase *cb, Class *cl, Object *o, APTR buf, ULONG w, ULONG h, ULONG flags)
{
  ULONG maxcnt, x, y;
  STRPTR b;

  if(flags & REKOFLAG_PREVIEW)
    return;

  b = (STRPTR) buf;
  for(maxcnt = w*h*3; maxcnt; --maxcnt) /* clear card */
    *(b++) = BACKCOL;

  maxcnt = GetFullWidth(cnt)*FULLHEIGHT;

  if(flags & REKOFLAG_PCMODE)
  {
    GetXY(0, &x, &y, flags);
    DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) buf, PBPAFMT_RGB, w*3, x*w, y*h, w, h);
  }

  while(cnt < maxcnt)
  {
    GetXY(cnt++, &x, &y, flags);
    if(!(flags & REKOFLAG_SOLITON) || x <= 13)
      DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) buf, PBPAFMT_RGB, w*3, x*w, y*h, w, h);
  }
}

#define EndConvI32(a)	(((a)>>24)|(((a)>>8)&0xFF00)|(((a)<<8)&0xFF0000)|((a)<<24))
#define EndConvI16(a)	((UWORD)(((a)>>8)|((a)<<8)))

static LONG GetPCREKO(struct ClassBase *cb, Class *cl, Object *o, BPTR fh,
struct BitMapHeader *bmhd, struct PCRekoHeader *h, STRPTR Title, ULONG flags)
{
  register ULONG CSize;
  LONG result = ERROR_OBJECT_WRONG_TYPE;

  flags |= REKOFLAG_PCMODE;
  h->rh_CardSize = EndConvI32(h->rh_CardSize);
  h->rh_Width = EndConvI16(h->rh_Width);
  h->rh_Height = EndConvI16(h->rh_Height);
  if(flags & REKOFLAG_SOLITON)
  {
    if(h->rh_CardsCnt > REKO_I-2)
      h->rh_CardsCnt = REKO_I-2;
  }
  else if(flags & REKOFLAG_PREVIEW)
    h->rh_CardsCnt = 5;
  /* Calculate sizes */
  CSize = h->rh_Width*h->rh_Height*(h->rh_Depth>>3);
  if(h->rh_CardsCnt && CSize && (h->rh_Depth == 8 || h->rh_Depth == 16) && h->rh_CardSize == CSize)
  {
    LONG ErrorLevel = 0, ErrorNumber = 0;
    ULONG ModeID;

     /* Fill in BitMapHeader information */
    bmhd->bmh_Width = bmhd->bmh_PageWidth = h->rh_Width*(flags & REKOFLAG_PREVIEW ? 1 : GetFullWidth(h->rh_CardsCnt));
    bmhd->bmh_Height = bmhd->bmh_PageHeight = h->rh_Height*(flags & REKOFLAG_PREVIEW ? 1 : FULLHEIGHT);
    bmhd->bmh_Depth = flags & REKOFLAG_16BIT ? 16 : 24;

    ModeID=BestModeID(BIDTAG_DesiredWidth, bmhd->bmh_Width, BIDTAG_DesiredHeight, bmhd->bmh_Height,
    BIDTAG_Depth, bmhd->bmh_Depth, TAG_DONE);

    SetDTAttrs(o, 0, 0, DTA_ObjName, Title, DTA_NominalHoriz, bmhd->bmh_Width, DTA_NominalVert, bmhd->bmh_Height,
    PDTA_SourceMode, PMODE_V43, PDTA_ModeID, ModeID, DTA_ErrorLevel, &ErrorLevel, DTA_ErrorNumber, &ErrorNumber, TAG_DONE);

    if(ErrorLevel)
      result = ErrorNumber;
    else if(h->rh_Depth == 16)
    {
      register UBYTE *d, *e;

      CSize = h->rh_Width*h->rh_Height*2+4;

      if((d = (UBYTE *) AllocVec(CSize+h->rh_Width*h->rh_Height*3, MEMF_PUBLIC)))
      {
	ULONG x, y;
        register ULONG i, j, card = 0;

	result = 0;
        e = d + CSize;
	  
	while(!result && card < h->rh_CardsCnt)
	{
	  if(Read(fh, d, CSize) != CSize)
	    result = ERROR_OBJECT_WRONG_TYPE;
	  else
	  {
	    j = 0;
	    for(i = 4; i < CSize; i += 2)
	    {
	      e[j++] = (d[i+1]<<1)&0xF8;		/* red */
	      e[j++] = (d[i+1]<<6 | d[i]>>2)&0xF8;	/* green */
	      e[j++] = (d[i]<<3)&0xF8;			/* blue */
	    }

	    GetXY(card+2, &x, &y, flags);
            DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
            h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
          }
          ++card;
        }
        if(!result && !(flags & REKOFLAG_PREVIEW))
        {
	  MakeBackCard(e, h->rh_Width, h->rh_Height);
	  GetXY(1, &x, &y, flags);
          DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
          h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
	  ClearCards(h->rh_CardsCnt+2, cb, cl, o, e, h->rh_Width, h->rh_Height, flags);
	}
	FreeVec(d);
      } /* AllocVec */
      else
	result = ERROR_NO_FREE_STORE;
    }
    else if(h->rh_Depth == 8)
    {
      register UBYTE *d, *e, *f, *g;

      CSize = h->rh_Width*h->rh_Height;

      if((d = (UBYTE *) AllocVec(CSize+256*3+h->rh_Width*h->rh_Height*3, MEMF_PUBLIC)))
      {
	ULONG x, y;
        register ULONG i, j, card = 0;

	result = 0;
        e = d + 256*3 + CSize;
        f = d + CSize;
	  
	while(!result && card < h->rh_CardsCnt)
	{
	  if(Read(fh, d, 256*2+4) != 256*2+4)
	    result = ERROR_OBJECT_WRONG_TYPE;
	  else
	  {
	    j = 0;
	    for(i = 4; i < (256)*2+4; i += 2)
	    {
	      f[j++] = (d[i+1]<<1)&0xF8;		/* red */
	      f[j++] = (d[i+1]<<6 | d[i]>>2)&0xF8;	/* green */
	      f[j++] = (d[i]<<3)&0xF8;			/* blue */
	    }
	    if(Read(fh, d, CSize) != CSize)
	      result = ERROR_OBJECT_WRONG_TYPE;
	    else
	    {
	      for(i = j = 0; i < CSize; ++i)
	      {
	        g = f + 3*d[i];
	        e[j++] = *(g++);
	        e[j++] = *(g++);
	        e[j++] = *g;
	      }

	      GetXY(card+2, &x, &y, flags);
              DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
              h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
            }
          }
          ++card;
        } /* while */
        if(!result && !(flags & REKOFLAG_PREVIEW))
	{
	  MakeBackCard(e, h->rh_Width, h->rh_Height);
	  GetXY(1, &x, &y, flags);
          DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
          h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
	  ClearCards(h->rh_CardsCnt+2, cb, cl, o, e, h->rh_Width, h->rh_Height, flags);
	}
	FreeVec(d);
      } /* AllocVec */
      else
        result = ERROR_NO_FREE_STORE;
    } /* Error ? */
  } /* data checks */
  return result;
}

static LONG GetWiz(struct ClassBase *cb, Class *cl, Object *o, BPTR fh,
struct BitMapHeader *bmhd, STRPTR Title, ULONG flags)
{
  LONG result = 0;

  flags |= REKOFLAG_WIZMODE;

  if(Seek(fh, -2, OFFSET_CURRENT) == -1)
    result = IoErr();
  else
  {
    int i;
    ULONG width=0, height=0, add = 0, x, y;
    struct Task* t;
    STRPTR e = 0;
    STRPTR mem;
    struct WizData wd;
 
    t = FindTask(0);
    for(i = 0; i < 13*4+1+add && !result; ++i)
    {
      if(Read(fh, &wd, WIZDATA_SIZE) == WIZDATA_SIZE)
      {
        wd.Width = EndConvI32(wd.Width);
        wd.Height = EndConvI32(wd.Height);
        wd.JPEGSize = EndConvI32(wd.JPEGSize);
        if(!i)
        {
          LONG ErrorLevel = 0, ErrorNumber = 0;
          ULONG ModeID;

          width = wd.Width;
          height = wd.Height;

          if(!(e = (STRPTR) AllocVec(width*height*3, MEMF_PUBLIC)))
            result = ERROR_NO_FREE_STORE;
          else
          {
            /* Fill in BitMapHeader information */
            bmhd->bmh_Width = bmhd->bmh_PageWidth = width*(flags & REKOFLAG_PREVIEW ? 1 :
            (flags & REKOFLAG_SOLITON ? NORMWIDTH : FULLWIDTH));
            bmhd->bmh_Height = bmhd->bmh_PageHeight = height*(flags & REKOFLAG_PREVIEW ? 1 : FULLHEIGHT);
            bmhd->bmh_Depth = flags & REKOFLAG_16BIT ? 16 : 24;

            ModeID=BestModeID(BIDTAG_DesiredWidth, bmhd->bmh_Width, BIDTAG_DesiredHeight, bmhd->bmh_Height,
            BIDTAG_Depth, bmhd->bmh_Depth, TAG_DONE);

            SetDTAttrs(o, 0, 0, DTA_ObjName, Title, DTA_NominalHoriz, bmhd->bmh_Width, DTA_NominalVert,
            bmhd->bmh_Height, PDTA_SourceMode, PMODE_V43, PDTA_ModeID, ModeID, DTA_ErrorLevel, &ErrorLevel,
            DTA_ErrorNumber, &ErrorNumber, TAG_DONE);
            if(ErrorLevel)
            {
              result = ErrorNumber;
              break;
            }
          }
        }
        if(!(flags & REKOFLAG_PREVIEW) || i == 1+3*13)
        {
          if(!(mem = AllocVec(wd.JPEGSize+30, MEMF_ANY)))
            result = ERROR_NO_FREE_STORE;
          else /* uses temporary file, does MEM-access work for all JPEG datatypes? */
          {
            if(Read(fh, mem+30, wd.JPEGSize) == wd.JPEGSize)
            {
              BPTR fh2;

              SPrintF(cb, mem, "T:REKODT_%08lx.jpg", t);
              if((fh2 = Open(mem, MODE_NEWFILE)))
              {
                if((Write(fh2, mem+30, wd.JPEGSize) == wd.JPEGSize))
                {
                  Object *obj;
                  struct BitMap *bmp;

                  Close(fh2); fh2 = 0;
                  if((obj = NewDTObject(mem,
                  DTA_GroupID           , GID_PICTURE,
                  OBP_Precision         , PRECISION_IMAGE,
                  DTA_SourceType        , DTST_FILE,
                  PDTA_DestMode         , PMODE_V43,
                  TAG_DONE)))
                  {
                    DoMethod(obj, DTM_PROCLAYOUT, NULL, 1);
                    GetDTAttrs(obj, PDTA_DestBitMap, &bmp, TAG_DONE);

	            GetXY(i, &x, &y, flags);

                    DoMethod(obj, PDTM_READPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
                    width*3, 0, 0, width, height);

                    DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
                    width*3, x*width, y*height, width, height);

                    DisposeDTObject(obj);
                  }
                  else
                    result = IoErr();
                }
                else
                  result = IoErr();

                if(fh2)
                  Close(fh2);
                DeleteFile(mem); /* remove the temporary file */
              }
              else
                result = IoErr();
            }
            else
              result = IoErr();

            FreeVec(mem);
          }
        } /* preview card? */
        else
        {
          if(Seek(fh, wd.JPEGSize, OFFSET_CURRENT) == -1)
            result = IoErr();
        }

        if(!result && i == 13*4 && !(flags & REKOFLAG_SOLITON)) /* additional cards */
        {
          if(Read(fh, &add, 4) == 4)
          {
            add = EndConvI32(add);
            if(add > 4)
              add = 0;
          }
          else
            add = 0;
        }
      } /* read header */
      else
        result = IoErr();
    }
    if(!result && !(flags & REKOFLAG_PREVIEW))
    {
      MakeBackCard(e, width, height);
      GetXY(57, &x, &y, flags);
      DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
      width*3, x*width, y*height, width, height);
      ClearCards(58, cb, cl, o, e, width, height, flags);
    }
    if(e)
      FreeVec(e);
  }
  return result;
}

static LONG MakeHAM(struct ClassBase *cb, Class *cl, Object *o, BPTR fh,
struct BitMapHeader *bmhd, struct RekoHeader *h, STRPTR Title, ULONG flags)
{
  ULONG CSize;
  LONG result = ERROR_OBJECT_WRONG_TYPE;

  /* Calculate sizes */
  CSize = (h->rh_Width*h->rh_Height*h->rh_Depth)>>3;
  if(h->rh_CardsCnt && CSize && h->rh_CardSize == CSize)
  {
    LONG ErrorLevel = 0, ErrorNumber = 0;
    ULONG ModeID;

     /* Fill in BitMapHeader information */
    bmhd->bmh_Width = bmhd->bmh_PageWidth = h->rh_Width*(flags & REKOFLAG_PREVIEW ? 1 : GetFullWidth(h->rh_CardsCnt));
    bmhd->bmh_Height = bmhd->bmh_PageHeight = h->rh_Height*(flags & REKOFLAG_PREVIEW ? 1 : FULLHEIGHT);
    bmhd->bmh_Depth = flags & REKOFLAG_16BIT ? 16 : 24;

    ModeID=BestModeID(BIDTAG_DesiredWidth, bmhd->bmh_Width, BIDTAG_DesiredHeight, bmhd->bmh_Height,
    BIDTAG_Depth, bmhd->bmh_Depth, TAG_DONE);

    SetDTAttrs(o, 0, 0, DTA_ObjName, Title, DTA_NominalHoriz, bmhd->bmh_Width, DTA_NominalVert, bmhd->bmh_Height,
    PDTA_SourceMode, PMODE_V43, PDTA_ModeID, ModeID, DTA_ErrorLevel, &ErrorLevel, DTA_ErrorNumber, &ErrorNumber, TAG_DONE);

    if(ErrorLevel)
      result = ErrorNumber;
    else if(h->rh_Depth == 8 || h->rh_Depth == 6)
    {
      UBYTE *Cr;
      ULONG i, dep;

      dep = h->rh_Depth;
      i = (1<<(dep-2))*3;
      if((Cr = (UBYTE *) AllocVec(i, MEMF_PUBLIC)))
      {
        if(Read(fh, Cr, i) == i)
        {
          register UBYTE *d, *e;

          if((d = (UBYTE *) AllocVec(CSize+h->rh_Width*h->rh_Height*3, MEMF_PUBLIC)))
          {
            ULONG j, k, l, m, card = 0, u;

	    result = 0;
	  
            l = h->rh_Width >> 3;
            u = dep*l;
	    while(!result && card < h->rh_CardsCnt)
	    {
	      if(Read(fh, d, CSize) != CSize)
	        result = ERROR_OBJECT_WRONG_TYPE;
	      else
	      {
	        ULONG x, y, v;
	        UBYTE *planar[8], image, last[3];

                e = d + CSize;

	        for(j = v = 0; j < h->rh_Height; ++j, v += u)
	        {
	          for(k = m = 0; k < dep; ++k, m += l)
	            planar[k] = d + m + v;

		  last[0] = Cr[0];
		  last[1] = Cr[1];
		  last[2] = Cr[2];
		  for(m = l; m; --m)
		  {
		    for(i = (1<<7); i; i >>= 1)
		    {
		      image = 0;
		      for(k = 0; k < dep; ++k)
		      {
		        image >>= 1;
		        image |= (*planar[k] & i) ? (1<<7) : 0;
		      }
		      k = image >> 6;
		      image <<= 2;
		      switch(k)
		      {
		      case 0: image >>= (8-dep+2); last[0] = Cr[image*3]; last[1] = Cr[image*3+1]; last[2] = Cr[image*3+2]; break;
		      case 1: last[2] = image; break;
		      case 2: last[0] = image; break;
		      case 3: last[1] = image; break;
		      }
		      *(e++) = last[0];
		      *(e++) = last[1];
		      *(e++) = last[2];
		    }
		    for(k = 0; k < dep; k++)
		      planar[k]++;
	          }
                }

	        GetXY(card, &x, &y, flags);
                DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) (d+CSize), PBPAFMT_RGB,
                h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
              }
              ++card;
            }
            if(!result)
	      ClearCards(h->rh_CardsCnt, cb, cl, o, d+CSize, h->rh_Width, h->rh_Height, flags);
            
	    FreeVec(d);
          } /* AllocVec */
          else
	    result = ERROR_NO_FREE_STORE;
	} /* Read */
      } /* AllocVec */
      else
        result = ERROR_NO_FREE_STORE;
    }
  } /* data checks */
  return result;
}

static LONG GetREKO(struct ClassBase *cb, Class *cl, Object *o, struct TagItem *attrs, ULONG flags)
{
  struct RekoHeader Header;
  LONG result = ERROR_OBJECT_WRONG_TYPE;
  struct BitMapHeader *bmhd = 0;
  BPTR fh = 0;
  STRPTR Title; /* Picture name */
  ULONG LSize, CSize, NumCol, ModeID;
  ULONG *MethodArray;

  Title = (STRPTR)GetTagData(DTA_Name, 0, attrs);
  GetDTAttrs(o, DTA_Handle, &fh, PDTA_BitMapHeader, &bmhd, DTA_Methods, &MethodArray, TAG_DONE);

  /* Now we search for the new PDTM_WRITEPIXELARRAY method to determine
     if it's the new V43 picture.datatype */
  while(*MethodArray != ~0 && *MethodArray != PDTM_WRITEPIXELARRAY)
    ++MethodArray;

  if(fh && bmhd)
  {
    if(Seek(fh, 0, OFFSET_BEGINNING)>=0)
    {
      if(Read(fh, &Header, HEADER_SIZE) == HEADER_SIZE)
      {
        if((((struct PCRekoHeader *) &Header)->rh_PCID == ID_PC) && (((struct PCRekoHeader *) &Header)->rh_ID == ID_REKO)
        && (*MethodArray == PDTM_WRITEPIXELARRAY))
	  result = GetPCREKO(cb, cl, o, fh, bmhd, (struct PCRekoHeader *) &Header, Title, flags);
	else if(Header.rh_ID == ID_WIZ)
	  result = GetWiz(cb, cl, o, fh, bmhd, Title, flags);
	else if(Header.rh_ID == ID_REKO)
	{
	  if(flags & REKOFLAG_SOLITON)
	  {
            if(Header.rh_CardsCnt > REKO_I)
              Header.rh_CardsCnt = REKO_I;
          }
          else if(flags & REKOFLAG_REKODT39)
          {
            if(Header.rh_CardsCnt > REKO_II)
              Header.rh_CardsCnt = REKO_II;
          }
          else if(flags & REKOFLAG_PREVIEW)
            Header.rh_CardsCnt = 7;
	  if(Header.rh_ModeID & HAM_KEY)
	  {
	    if((*MethodArray == PDTM_WRITEPIXELARRAY) && !(flags & REKOFLAG_HAMDIRECT))
	      return MakeHAM(cb, cl, o, fh, bmhd, &Header, Title, flags);
	    else if(flags & REKOFLAG_SOLITON)
	      return 0;
	  }
	  /* Calculate sizes */
	  NumCol = 1<<((Header.rh_ModeID & HAM_KEY) ? Header.rh_Depth-2 : Header.rh_Depth);
	  LSize = Header.rh_Width>>3; /* Width in bytes */
	  CSize = LSize*Header.rh_Height*Header.rh_Depth; /* Card size in bytes */
	  if(Header.rh_CardsCnt && CSize && Header.rh_Depth>=3 && Header.rh_CardSize == CSize)
	  {
	    /* Fill in BitMapHeader information */
	    bmhd->bmh_Width = bmhd->bmh_PageWidth = Header.rh_Width*(flags & REKOFLAG_PREVIEW ? 1 :
	    GetFullWidth(Header.rh_CardsCnt));
	    bmhd->bmh_Height = bmhd->bmh_PageHeight = Header.rh_Height*(flags & REKOFLAG_PREVIEW ? 1 : FULLHEIGHT);
	    bmhd->bmh_Depth = Header.rh_Depth;

	    /* Get display mode id */
	    if((ModeID=BestModeID(Header.rh_ModeID & HAM_KEY ? BIDTAG_DIPFMustHave : TAG_IGNORE, DIPF_IS_HAM,
	    BIDTAG_DesiredWidth, bmhd->bmh_Width, BIDTAG_DesiredHeight, bmhd->bmh_Height,
	    BIDTAG_Depth, Header.rh_Depth, TAG_DONE)) != INVALID_ID)
	    {
  	      UBYTE *CMap = 0;		/* in real "struct ColorRegister *" */
	      ULONG *CRegs = 0;

	      /* Set colors */
	      SetDTAttrs(o,NULL,NULL,PDTA_NumColors,NumCol,TAG_DONE);
	      GetDTAttrs(o,PDTA_ColorRegisters,&CMap,PDTA_CRegs,&CRegs,TAG_DONE);
	      if(CMap && CRegs)
	      {
	        NumCol *= 3;
	        if(Read(fh,CMap,NumCol)==NumCol)
	        {
	          register ULONG i;
		  struct BitMap *bm;
		  register ULONG *a;
		  register UBYTE *b;
		  
		  a = CRegs;
		  b = CMap;

		  while(NumCol--)
  		  {
		    i = *(b++);
		    i = (i<<8)+i;
		    *(a++) = (i<<16)+i;
		  }

	          /* Prepare bitmap */
	          if((bm=AllocBitMap(bmhd->bmh_Width, bmhd->bmh_Height, Header.rh_Depth,
	          (BMF_CLEAR | BMF_INTERLEAVED | BMF_DISPLAYABLE), 0)))
	          {
		    STRPTR Buffer;

	            /* Allocate temporary buffer */
		    if((Buffer = (STRPTR) AllocVec(CSize, MEMF_PUBLIC)))
		    {
		      result = 0;
		      /* Read data in 1-card chunks */
		      for(i=0; !result && i < Header.rh_CardsCnt; ++i)
		      {
			if(Read(fh,Buffer,CSize) != CSize)
			  result = ERROR_OBJECT_WRONG_TYPE;
			else
			{
			  ULONG x,y;
			  register ULONG k, j, DstOffs, bpr, h;

  			  bpr = bm->BytesPerRow;
  			  b = Buffer;
  			  h = Header.rh_Height;

  			  GetXY(i,&x,&y, flags);
  			  DstOffs=y*h*bpr+x*LSize;
			  while(h--)
			  {
			    for(k=0; k < Header.rh_Depth; k++)
    			    {
      			      for(j = 0; j < LSize; ++j)
        			bm->Planes[k][DstOffs+j] = *(b++);
    			    }
    			    DstOffs += bpr;
			  }
			}
		      }
	              FreeVec(Buffer);

		      /* Set attributes of destination picture */
		      if(!result)
		        SetDTAttrs(o, 0, 0, DTA_ObjName, Title, DTA_NominalHoriz, bmhd->bmh_Width,
			DTA_NominalVert, bmhd->bmh_Height, PDTA_BitMap, bm, PDTA_ModeID, ModeID,
			PDTA_SourceMode, PMODE_V42, PDTA_DestMode, PMODE_V42, TAG_DONE);
		    } /* AllocVec */
		    else
		      result = ERROR_NO_FREE_STORE;
		    if(result)
	              FreeBitMap(bm);
	          } /* AllocBitmap */
	        } /* Read colortable */
	      } /* CMap && CRegs */
	    } /* BestModeID */
	  } /* data checks */
	} /* ID_REKO ? */
      } /* read header */
    } /* seek to begin */
  } /* fh && bmhd */
  return result;
}

ASM(Object *) Dispatch(REG(a0, Class *cl), REG(a2, Object *o), REG(a1, Msg msg))
{
  struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
  Object *Obj;

  switch(msg->MethodID)
  {
    case OM_NEW: /* We know this method */
      if((Obj = (Object *)DoSuperMethodA(cl,o,msg)))
      {
        UBYTE dtmode[50] = "NORMAL", *ptr;
        ULONG flags = 0;

        GetVar("REKODTMODE", (STRPTR) &dtmode, 50, GVF_GLOBAL_ONLY);
        ptr = dtmode;
        while(*ptr)
        {
          switch(*ptr)
          {
          case 'm': case 'M': flags |= REKOFLAG_MREKO; break;           /* MREKOMODE */
          case 'r': case 'R': flags |= REKOFLAG_REKODT39; break;        /* REKODT39MODE */
          case 'p': case 'P': flags |= REKOFLAG_PREVIEW; break;		/* PREVIEW */
          case 's': case 'S': flags |= REKOFLAG_SOLITON; break;		/* SOLITON */
          case 'h': case 'H': flags |= REKOFLAG_HAMDIRECT; break;	/* HAMDIRECT */
          case '1':	      flags |= REKOFLAG_16BIT; break;		/* 16BIT */
       /* case '2': */							/* 24BIT */
       /* case 'n': case 'N': */					/* NORMAL */
          }
          while(*ptr && *(ptr++) != ',')
            ;
        }
        if(flags & REKOFLAG_SOLITON)
          flags &= ~(REKOFLAG_HAMDIRECT|REKOFLAG_MREKO|REKOFLAG_REKODT39|REKOFLAG_PREVIEW);
        else if(flags & REKOFLAG_PREVIEW)
          flags &= ~(REKOFLAG_REKODT39|REKOFLAG_MREKO);
        else if(flags & REKOFLAG_MREKO)
          flags &= ~(REKOFLAG_REKODT39);

        if((flags = GetREKO(cb, cl, Obj, ((struct opSet *)msg)->ops_AttrList, flags)))
        {
          SetIoErr(flags);
          CoerceMethod(cl, Obj, OM_DISPOSE);
          return 0;
        }
        else
          SetIoErr(0);
      }
      break;
    default: /* Let the superclass handle it */
      Obj = (Object *)DoSuperMethodA(cl, o, msg);
      break;
  }
  return Obj;
}

Decoder

References

Picture.class 41.00

OM_DISPOSE function DT_DisposeMethod
OM_GET function DT_GetMethod
OM_NEW function DT_NewMethod
OM_SET alias OM_UPDATE or function DT_SetMethod
GM_GOACTIVE function DT_GoActiveMethod
GM_HANDLEINPUT function DT_HandleInputMethod
GM_LAYOUT function DT_Layout
GM_RENDER function DT_Render
DTM_ASYNCLAYOUT function DT_AsyncLayout
DTM_DRAW function DT_Draw
DTM_FRAMEBOX function DT_FrameBox
DTM_OBTAINDRAWINFO function DT_ObtainDrawInfo
DTM_PROCLAYOUT function DT_ProcLayout
DTM_RELEASEDRAWINFO function DT_ReleaseDrawInfo
PDTM_READPIXELARRAY function PDT_ReadPixelArray
PDTM_SCALE function PDT_Scale
PDTM_WRITEPIXELARRAY function PDT_WritePixelArray

sound.class 41.11

OM_DISPOSE function Sound_DISPOSE
OM_GET function Sound_GET
OM_NEW function Sound_NEW
OM_SET function Sound_SET
OM_UPDATE function Sound_UPDATE
GM_DOMAIN function Sound_DOMAIN
GM_GOINACTIVE function Sound_GOINACTIVE
GM_HANDLEINPUT function Sound_HANDLEINPUT alias GM_GOACTIVE 
GM_HITTEST function Sound_HITTEST alias GM_HELPTEST
GM_LAYOUT function Sound_LAYOUT alias DTM_PROCLAYOUT
GM_RENDER function Sound_RENDER
DTM_CLEARSELECTED function Sound_CLEARSELECTED
DTM_WRITE function Sound_WRITE alias DTM_COPY
DTM_DRAW function Sound_DRAW
DTM_OBTAINDRAWINFO function Sound_OBTAINDRAWINFO
DTM_RELEASEDRAWINFO function Sound_RELEASEDRAWINFO
DTM_REMOVEDTOBJECT function Sound_REMOVEDTOBJECT
DTM_SELECT function Sound_SELECT
DTM_TRIGGER function Sound_TRIGGER
This article is issued from Wikibooks. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.