/* OpenAmiga.org
 *  This file is part of the OpenAmiga "xfdmaster library project"
 *
 * For more information look at:
 *   http://openamiga.org/?function=viewproject&projectid=67
 */

/****************************************************************************
*   XFD library system for cruncher handling
*   Copyright (C) 1994-1998 by Georg Hörmann
*   Copyright (C) 1998 by Dirk Stöcker <soft@dstoecker.de>
*   Copyright (C) 2014 by Fredrik Wikström <fredrik@a500.org>
*
*   This library is free software; you can redistribute it and/or
*   modify it under the terms of the GNU Lesser General Public
*   License as published by the Free Software Foundation; either
*   version 2.1 of the License, or (at your option) any later version.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   Lesser General Public License for more details.
*
*   You should have received a copy of the GNU Lesser General Public
*   License along with this library; if not, write to the Free Software
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
****************************************************************************/

#include <interfaces/xfdmaster.h>
#include "../xfdmaster_vectors.h"
#include "../xfdmaster_internal.h"

/****** xfdmaster.library/xfdRecogBuffer ******************************************
*
*   NAME
*      xfdRecogBuffer -- Description
*
*   SYNOPSIS
*      BOOL xfdRecogBuffer(struct xfdBufferInfo * bufferinfo);
*
*   FUNCTION
*
*   INPUTS
*       bufferinfo - 
*
*   RESULT
*       The result ...
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*
*****************************************************************************
*
*/

BOOL _xfdMaster_xfdRecogBuffer(struct xfdMasterIFace *Self,
	struct xfdBufferInfo *bufferinfo)
{
	DEBUGF("xfdRecogBuffer(0x%08lx, 0x%08lx)\n", Self, bufferinfo);
	struct xfdMasterBase *libBase = (struct xfdMasterBase *)Self->Data.LibBase;
	struct ExecIFace *IExec = libBase->xfdm_IExec;
	struct xfdSlave *slave;
	struct xfdRecogResult recogresult;

	DEBUGF("xfdbi_SourceBuffer:     0x%08lx\n", bufferinfo->xfdbi_SourceBuffer);
	DEBUGF("xfdbi_SourceBufLen:     %lu\n",     bufferinfo->xfdbi_SourceBufLen);
	DEBUGF("xfdbi_Slave:            0x%08lx\n", bufferinfo->xfdbi_Slave);
	DEBUGF("xfdbi_PackerName:       0x%08lx\n", bufferinfo->xfdbi_PackerName);
	DEBUGF("xfdbi_PackerFlags:      0x%04lx\n", bufferinfo->xfdbi_PackerFlags);
	DEBUGF("xfdbi_Error:            %lu\n",     bufferinfo->xfdbi_Error);
	DEBUGF("xfdbi_TargetBuffer:     0x%08lx\n", bufferinfo->xfdbi_TargetBuffer);
	DEBUGF("xfdbi_TargetBufMemType: 0x%08lx\n", bufferinfo->xfdbi_TargetBufMemType);
	DEBUGF("xfdbi_TargetBufLen:     %lu\n",     bufferinfo->xfdbi_TargetBufLen);
	DEBUGF("xfdbi_TargetBufSaveLen: %lu\n",     bufferinfo->xfdbi_TargetBufSaveLen);
	DEBUGF("xfdbi_DecrAddress:      %lu\n",     bufferinfo->xfdbi_DecrAddress);
	DEBUGF("xfdbi_JmpAddress:       %lu\n",     bufferinfo->xfdbi_JmpAddress);
	DEBUGF("xfdbi_Special:          0x%08lx\n", bufferinfo->xfdbi_Special);
	DEBUGF("xfdbi_Flags:            0x%04lx\n", bufferinfo->xfdbi_Flags);
	DEBUGF("xfdbi_Reserved0:        %lu\n",     bufferinfo->xfdbi_Reserved0);
	DEBUGF("xfdbi_MinTargetLen:     %lu\n",     bufferinfo->xfdbi_MinTargetLen);
	DEBUGF("xfdbi_FinalTargetLen:   %lu\n",     bufferinfo->xfdbi_FinalTargetLen);
	DEBUGF("xfdbi_UserTargetBuf:    0x%08lx\n", bufferinfo->xfdbi_UserTargetBuf);
	DEBUGF("xfdbi_UserTargetBufLen: %lu\n",     bufferinfo->xfdbi_UserTargetBufLen);
	DEBUGF("xfdbi_MinSourceLen:     %lu\n",     bufferinfo->xfdbi_MinSourceLen);

	if (bufferinfo->xfdbi_SourceBuffer == NULL ||
		bufferinfo->xfdbi_SourceBufLen == 0)
	{
		bufferinfo->xfdbi_Error = XFDERR_NOSOURCE;
		return FALSE;
	}

	slave = libBase->xfdm_FirstSlave;
	while (slave != NULL) {
		if (slave->xfds_Version <= XFDS_VERSION &&
			slave->xfds_MasterVersion <= libBase->LibNode.lib_Version &&
			slave->xfds_RecogBuffer != NULL &&
			((slave->xfds_PackerFlags & XFDPFF_EXTERN) == 0 ||
			(bufferinfo->xfdbi_Flags & XFDFF_RECOGEXTERN) != 0) &&
			((slave->xfds_PackerFlags & XFDPFF_USERTARGET) != 0 ||
			(bufferinfo->xfdbi_Flags & XFDFF_RECOGUSERTARGET) == 0) &&
			((slave->xfds_PackerFlags & XFDPFF_RECOGLEN) != 0 ||
			(bufferinfo->xfdbi_Flags & XFDFF_RECOGTARGETLEN) == 0) &&
			(slave->xfds_Version < 2 ||
			bufferinfo->xfdbi_SourceBufLen >= slave->xfds_MinBufferSize))
		{
			ULONG res;

			recogresult.xfdrr_MinTargetLen = 0;
			recogresult.xfdrr_FinalTargetLen = 0;
			recogresult.xfdrr_MinSourceLen = 0;

			if (IExec->IsNative(slave->xfds_RecogBuffer)) {
				xfdRecogBufferFunc func = (xfdRecogBufferFunc)slave->xfds_RecogBuffer;
				res = func(Self, bufferinfo->xfdbi_SourceBuffer,
					bufferinfo->xfdbi_SourceBufLen, &recogresult);
			} else {
				res = IExec->EmulateTags(slave->xfds_RecogBuffer,
					ET_SaveParamRegs, TRUE,
					ET_RegisterA0,    bufferinfo->xfdbi_SourceBuffer,
					ET_RegisterD0,    bufferinfo->xfdbi_SourceBufLen,
					ET_RegisterA1,    &recogresult,
					ET_RegisterA6,    libBase,
					TAG_END);
			}
			if (res) {
				bufferinfo->xfdbi_Slave = slave;
				bufferinfo->xfdbi_PackerName = slave->xfds_PackerName;
				bufferinfo->xfdbi_PackerFlags = slave->xfds_PackerFlags & ~XFDPFF_EXTERN;
				bufferinfo->xfdbi_MaxSpecialLen = slave->xfds_MaxSpecialLen;
				bufferinfo->xfdbi_MinTargetLen = recogresult.xfdrr_MinTargetLen;
				bufferinfo->xfdbi_FinalTargetLen = recogresult.xfdrr_FinalTargetLen;
				bufferinfo->xfdbi_MinSourceLen = recogresult.xfdrr_MinSourceLen;
				return TRUE;
			}
		}
		slave = slave->xfds_Next;
	}

	bufferinfo->xfdbi_Slave = NULL;
	bufferinfo->xfdbi_PackerName = NULL;
	bufferinfo->xfdbi_PackerFlags = 0;
	bufferinfo->xfdbi_Error = XFDERR_UNKNOWN;
	return FALSE;
}

