
#include "Snap.h"

/* This is just plain clipboard handling */
#include <setjmp.h>

/* alredy defined in Include 2.0 
#define ID(a,b,c,d) ((a << 24L) | (b << 16L) | (c << 8L) | (d))

#define ID_CAT  ID('C','A','T',' ')
#define ID_FORM ID('F','O','R','M')
#define ID_FTXT ID('F','T','X','T')
#define ID_CHRS ID('C','H','R','S')
*/

#define SAFE(cond, jmp_buf)  { if (!(cond)) longjmp(jmp_buf,-1); }

IMPORT struct IOClipReq *ClipReq;

VOID CBFInit(struct CBFHandle *CBFH)
{
	if (CBFH->Type == CBFCLIP)
	{
		CBFH->Handle.ClipReq->io_Error = 0;
		CBFH->Handle.ClipReq->io_Offset = 0L;
		CBFH->Handle.ClipReq->io_ClipID = 0L;
	}
}

VOID CBFEndWrite(struct CBFHandle *CBFH)
{
	if (CBFH->Type == CBFCLIP)
	{
		CBFH->Handle.ClipReq->io_Command = CMD_UPDATE;
		DoIO((struct IORequest *)CBFH->Handle.ClipReq);
	}
}

VOID CBFEndRead(struct CBFHandle *CBFH)
{
	if (CBFH->Type == CBFCLIP)
	{
		CBFH->Handle.ClipReq->io_Command = CMD_READ;
		CBFH->Handle.ClipReq->io_Offset = 2000000000;
		CBFH->Handle.ClipReq->io_Length = 1;
		CBFH->Handle.ClipReq->io_Data = (STRPTR) 0;
		DoIO((struct IORequest *)CBFH->Handle.ClipReq);
	}
}

ULONG CBFSeek(struct CBFHandle *CBFH, LONG Offset, LONG Origin)
{
	if (CBFH->Type == CBFCLIP)
	{
		switch (Origin)
		{
		case OFFSET_CURRENT:
			{
				CBFH->Handle.ClipReq->io_Offset += Offset;
				return CBFH->Handle.ClipReq->io_Offset;
			}
		case OFFSET_BEGINNING:
			{
				CBFH->Handle.ClipReq->io_Offset = Offset;
				return CBFH->Handle.ClipReq->io_Offset;
			}
		default:
			{
				return 2000000000;
			}
		}
	}
	else
	{
		return (ULONG) Seek(CBFH->Handle.File, Offset, Origin);
	}
	return 0;
}

LONG CBFWrite(struct CBFHandle * CBFH, STRPTR Buf, ULONG BufSize)
{
	if (CBFH->Type == CBFCLIP)
	{
		CBFH->Handle.ClipReq->io_Command = CMD_WRITE;
		CBFH->Handle.ClipReq->io_Data = Buf;
		CBFH->Handle.ClipReq->io_Length = BufSize;
		DoIO((struct IORequest *)CBFH->Handle.ClipReq);
		return (CBFH->Handle.ClipReq->io_Error ? -1 : 0);
	}
	else
	{
		return Write(CBFH->Handle.File, (char *)Buf, BufSize);
	}
}

LONG CBFRead(struct CBFHandle *CBFH, STRPTR Buf, ULONG BufSize)
{
	if (CBFH->Type == CBFCLIP)
	{
		CBFH->Handle.ClipReq->io_Command = CMD_READ;
		CBFH->Handle.ClipReq->io_Data = Buf;
		CBFH->Handle.ClipReq->io_Length = BufSize;
		DoIO((struct IORequest *)CBFH->Handle.ClipReq);
		return (CBFH->Handle.ClipReq->io_Error ? -1 : 0);
	}
	else
	{
		return Read(CBFH->Handle.File, (char *)Buf, BufSize);
	}
}

jmp_buf failure;

VOID SaveClip(UBYTE * SnapSpace, ULONG SnapSize)
{
	ULONG Len;
	struct CBFHandle CBFH;

	CBFH.Type = CBFCLIP;
	CBFH.Handle.ClipReq = ClipReq;

	CBFInit(&CBFH);
	CBFWrite(&CBFH, (STRPTR) "FORM", 4L);
	Len = (SnapSize + 13) & ~1;
	CBFWrite(&CBFH, (STRPTR) & Len, 4L);
	CBFWrite(&CBFH, (STRPTR) "FTXT", 4L);
	CBFWrite(&CBFH, (STRPTR) "CHRS", 4L);
	Len = SnapSize;
	CBFWrite(&CBFH, (STRPTR) & Len, 4L);
	CBFWrite(&CBFH, SnapSpace, Len);
	if (SnapSize & 1)
	{
		CBFWrite(&CBFH, (STRPTR) "\0", 1L);
	}
	CBFEndWrite(&CBFH);
}

struct Snap *FetchClip()
{
	struct Snap *Snap = NULL;
	ULONG ID[3];
	struct CBFHandle CBFH;
	WORD done = 0;

	CBFH.Type = CBFCLIP;
	CBFH.Handle.ClipReq = ClipReq;

	if (setjmp(failure))
	{
		if (Snap)
		{
			FreeMem(Snap, Snap->Size);
		}
		CBFEndRead(&CBFH);
		return NULL;
	}

	CBFInit(&CBFH);
	SAFE(CBFRead(&CBFH, (STRPTR) & ID[0], 12) != -1L, failure);
	if (ID[0] != ID_CAT)
	{
		CBFSeek(&CBFH, -12, OFFSET_CURRENT);
	}
	while (!done)
	{
		SAFE(CBFRead(&CBFH, (STRPTR) & ID[0], 12) != -1L, failure);
		switch (ID[2])
		{
		case ID_FTXT:
			{
				SAFE(CBFRead(&CBFH, (STRPTR) & ID[0], 8) != -1L, failure);
				SAFE(ID[0] == ID_CHRS, failure);
				Snap = AllocMem(sizeof (struct Snap) + ID[1],
						MEMF_PUBLIC | MEMF_CLEAR);

				SAFE(Snap, failure);
				Snap->Size = sizeof (struct Snap) + ID[1];

				SAFE(CBFRead(&CBFH, (STRPTR) & Snap->Chars[0], Snap->Size) != -1L,
				     failure);
				done = 1;
				break;
			}
		default:
			{
				SAFE(CBFSeek(&CBFH, ID[1] + (ID[1] & 1) - 4, OFFSET_CURRENT),
				     failure);
				break;
			}
		}
	}
	CBFEndRead(&CBFH);
	return (Snap);
}
