/*
 * GrabPointer.c
 * Grab OS3.0 mouse pointers from running code.
 * GrabPointer installs itself into NewObject() and grabs
 * all "pointerclass" objects as C source to stdout.
 *
 * Link with no stack checking.
 * By David Ekholm
 * v1.0 (95-12-03)
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <exec/types.h>
#include <proto/intuition.h>	/* DisplayBeep() */ 
#include <proto/exec.h>
#include <dos/dos.h> 			/* SIGBREAKF_CTRL_C */
#include <intuition/intuition.h>
#include <intuition/classusr.h>
#include <intuition/pointerclass.h>
#include <proto/utility.h>
#include <graphics/gfx.h>

#define NEWOBJECTA_OFFS -0x27c

UBYTE Version[] = "$VER: GrabPointer 1.0 " __AMIGADATE__ "";

struct IntuitionBase *IntuitionBase;
struct Library *UtilityBase;

int I;   /* Incremented at each invocation of NewObject.."pointerclass" */

char *Xresnames[] = {
	"POINTERXRESN_DEFAULT",
	"POINTERXRESN_140NS",
	"POINTERXRESN_70NS",
	"POINTERXRESN_35NS",
	"POINTERXRESN_SCREENRES",
	"POINTERXRESN_LORES",
	"POINTERXRESN_HIRES"
};

char *Yresnames[] = {
	"POINTERYRESN_DEFAULT",
	"Unknown",
	"POINTERYRESN_HIGH",
	"POINTERYRESN_HIGHASPECT",
	"POINTERYRESN_SCREENRES",
	"POINTERYRESN_SCREENRESASPECT"
};

APTR __asm (*real_new_objectA)(register __a0 struct IClass *classPtr,
										 register __a1 UBYTE *classID,
										 register __a2 struct TagItem *tagList,
										 register __a6 struct IntuitionBase *IntuitionBase);


void print_planes(struct BitMap *bm)
{
	int i,j;
	if (!bm->Depth) return;
	printf("UWORD __chip grab%d_pl[][%d] =\n",I, bm->Rows);
	printf("{\n");
	for (i=0; i<bm->Depth; i++) {
		if (i) printf(",\n\n");
		printf("\t/* Plane %d */ {\n\t", i);
		for (j=0; j<bm->Rows; j++) {
			if (j) printf(",\n\t");
			switch (bm->BytesPerRow) {
			case 2:
				printf("0x%04X", ((UWORD *)bm->Planes[i])[j]); 
				break;
			case 4:
				printf("0x%08X", ((ULONG *)bm->Planes[i])[j]); 
				break;
			default:
				printf("/* Sorry. This number of BytesPerRow is not supported */");
			}
		}
		printf(" }");
	}
	printf("\n};\n\n");
}

void print_BitMap(struct BitMap *bm)
{
	int i;

	printf("struct BitMap grab%d_bm = {\n", I);
	printf("\t%d,\t/* UWORD BytesPerRow */\n", bm->BytesPerRow);
	printf("\t%d,\t/* UWORD Rows */\n", bm->Rows);
	printf("\t%d,\t/* UBYTE Flags */\n", bm->Flags);
	printf("\t%d,\t/* UBYTE Depth */\n", bm->Depth);
	printf("\t%d,\t/* UWORD pad */\n", bm->pad);
	printf("\t{ ");
	for (i=0; i<bm->Depth; i++) {
		if (i) printf(", ");
		printf("(PLANEPTR)&grab%d_pl[%d]",I, i);
	}
	printf(" } /* PLANEPTR Planes[8] */\n");
	printf("};\n\n");
}

/*
char *bitnames(ULONG bitmask, char *names[], int n, char *buf)
{
	int i;
	buf[0] = '\0';

	for (i=0; i<n; i++)
		if (bitmask & i) {
			if (i) strcat(buf, "| ");
			strcat(buf, names[i]);
		}
	return buf;
}
*/

void print_funccall(struct TagItem *tagList)
{
	struct TagItem *tag;
	printf("/*\n");
	printf("\tAPTR grab%d_pointer;\n", I);
	printf("\tgrab%d_pointer = NewObject(NULL, \"pointerclass\",\n", I);
	if (tag = FindTagItem(POINTERA_BitMap, tagList))
		printf("\t\tPOINTERA_BitMap, &grab%d_bm", I);
	if (tag = FindTagItem(POINTERA_XOffset, tagList))
		printf(",\n\t\tPOINTERA_XOffset, %d", tag->ti_Data);
	if (tag = FindTagItem(POINTERA_YOffset, tagList))
		printf(",\n\t\tPOINTERA_YOffset, %d", tag->ti_Data);
	if (tag = FindTagItem(POINTERA_WordWidth, tagList))
		printf(",\n\t\tPOINTERA_WordWidth, %d", tag->ti_Data);
	if (tag = FindTagItem(POINTERA_XResolution, tagList))
		printf(",\n\t\tPOINTERA_XResolution, %s", Xresnames[tag->ti_Data]);
	if (tag = FindTagItem(POINTERA_YResolution, tagList))
		printf(",\n\t\tPOINTERA_YResolution, %s", Yresnames[tag->ti_Data]);
	printf("\n\t);\n");
	printf("*/\n");

}

APTR __saveds __asm new_objectA(register __a0 struct IClass *classPtr,
										  register __a1 UBYTE *classID,
										  register __a2 struct TagItem *tagList)
{
	struct BitMap *bm;
	if (!classPtr && !strcmp(classID, POINTERCLASS)) {
		if (bm = (struct BitMap *)GetTagData(POINTERA_BitMap, 0, tagList)) {
			print_planes(bm);
			print_BitMap(bm);
			print_funccall(tagList);
			printf("\n\n/****************************************************************************/\n\n");
			++I;
		}
	}
	return real_new_objectA(classPtr, classID, tagList, IntuitionBase);
}

void addpatch(void)
{
	real_new_objectA = SetFunction((struct Library *)IntuitionBase,
		NEWOBJECTA_OFFS, (APTR)new_objectA);
}

void deletepatch(void)
{
	if (real_new_objectA) {
		SetFunction((struct Library *)IntuitionBase,	NEWOBJECTA_OFFS, (APTR)real_new_objectA);
		real_new_objectA = NULL;
	}
}

void main()
{
	if ((IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37))) {
		if ((UtilityBase = OpenLibrary("utility.library",37))) {
			addpatch();
			fprintf(stderr, "%s by David Ekholm, Datadosen.\n", &Version[6]);
			fprintf(stderr, "Grab OS3.0 mouse pointers from running code.\n");
			fprintf(stderr, "Patch installed in NewObjectA(). Press CTRL-C to remove.\n");
			Wait(SIGBREAKF_CTRL_C);
			deletepatch();
			fprintf(stderr, "Patch removed.\n");
		}
		if (UtilityBase) CloseLibrary(UtilityBase);
	}
	if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
}
