/*
** $VER: Encode.c (22.5.95) by Flavio Stanchina
*/

#include <exec/types.h>
#include <dos/dos.h>
#include <dos/stdio.h>

#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#include <clib/dos_protos.h>

#include <string.h>

#if defined(__SASC)
#include <proto/exec.h>
#include <proto/utility.h>
#include <proto/dos.h>
#endif

#include "FSCode.h"
#include "CRC32.h"

static BPTR OpenOut(struct FSData *fsd)
{
	fsd->Part += 1;

	if (fsd->To)
	{
		if (fsd->Multi)
			SPrintf(fsd->Temp, NameFmt, fsd->To, fsd->Part);
		else
			strcpy(fsd->Temp, fsd->To);

		if (fsd->Out = Open(fsd->Temp, MODE_NEWFILE))
		{
			SetVBuf(fsd->Out, NULL, BUF_FULL, 16384);
			fsd->close_out = TRUE;
		}
		else
		{
			MyPrintFault(fsd, IoErr(), fsd->Temp);
			return 0;
		}
	}
	else fsd->Out = Output();

	FPutC(fsd->Out, '\n');

	if (fsd->Multi)
		FPrintf(fsd->Out, MultiFmt, fsd->Part, fsd->Parts, FilePart(fsd->File));
	else
		FPrintf(fsd->Out, StartFmt, FilePart(fsd->File));

	return fsd->Out;
}

static VOID FlushOut(struct FSData *fsd)
{
	if (fsd->TempCnt)
	{
		FWrite(fsd->Out, fsd->Temp, 1, fsd->TempCnt);
		FPutC (fsd->Out, '\n');

		fsd->Line   += 1;
		fsd->TempCnt = 0;
	}
}

static VOID CloseOut(struct FSData *fsd)
{
	if (fsd->Out)
	{
		FlushOut(fsd);
		FPrintf(fsd->Out, EndFmt, fsd->Size, fsd->CRC);
		if (fsd->close_out) MyClose(fsd, fsd->Out);
		fsd->Out = 0;
	}
}

VOID DoEncode(STRPTR out, ULONG in, struct Library *UtilBase);
//{
//	out[4] = (in % 85) + 42; in /= 85;
//	out[3] = (in % 85) + 42; in /= 85;
//	out[2] = (in % 85) + 42; in /= 85;
//	out[1] = (in % 85) + 42; in /= 85;
//	out[0] = (in     ) + 42;
//}

LONG Encode(struct FSData *fsd)
{
	ULONG *in;
	UBYTE *out;
	ULONG tmp = 0;

	fsd->Size = 0;
	fsd->CRC  = 0xFFFFFFFF; /* preload shift register, per CRC-32 spec */

	out = fsd->Temp;

	while((LONG)(fsd->BufCnt = Read(fsd->In, fsd->Buffer, FSD_BUFSIZ)) > 0)
	{
		in = (ULONG *)fsd->Buffer;

		do {
			if ((fsd->TempCnt == 0) && (fsd->Line == 0))
				OpenOut(fsd);

			if (fsd->BufCnt < 4)
			{
				fsd->CRC = CRC32_blocks((UBYTE *)in, fsd->BufCnt, fsd->CRC);

				tmp = *in;
				switch(fsd->BufCnt)
				{
					case 1: tmp >>= 8;
					case 2: tmp >>= 8;
					case 3: tmp >>= 8;
				}

				DoEncode(out, tmp, UtilityBase);

				switch(fsd->BufCnt)
				{
					case 1: out[2] = '#';
					case 2: out[1] = '#';
					case 3: out[0] = '#';
				}

				fsd->Size  += fsd->BufCnt;
				fsd->BufCnt = 0;
			}
			else
			{
				fsd->CRC = CRC32_blocks((UBYTE *)in, 4, fsd->CRC);
				DoEncode(out, *in++, UtilityBase);

				fsd->Size   += 4;
				fsd->BufCnt -= 4;
			}

			out += 5;
			fsd->TempCnt += 5;

			if (fsd->TempCnt == 75)
			{
				if (CheckSignal(SIGBREAKF_CTRL_C)) return -3;

				FlushOut(fsd);
				out = fsd->Temp;

				// close block only if more than one line left
				if (fsd->Multi && (fsd->Line >= fsd->Lines) && ((fsd->RealSize - fsd->Size) > 60))
				{
					CloseOut(fsd);
					fsd->Line = 0;
				}
			}
		} while(fsd->BufCnt > 0);
	}

	if ((LONG)(fsd->BufCnt) == -1)
		MyPrintFault(fsd, IoErr(), "read error");

	CloseOut(fsd);

	return 0;
}
