/* 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/xfdTestHunkStructureFlags ******************************************
*
*   NAME
*      xfdTestHunkStructureFlags -- Description
*
*   SYNOPSIS
*      UWORD xfdTestHunkStructureFlags(APTR buffer, ULONG length, 
*          ULONG flags);
*
*   FUNCTION
*
*   INPUTS
*       buffer - 
*       length - 
*       flags - 
*
*   RESULT
*       The result ...
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*
*****************************************************************************
*
*/

UWORD _xfdMaster_xfdTestHunkStructureFlags(struct xfdMasterIFace *Self, APTR buffer,
	ULONG length, ULONG flags)
{
	DEBUGF("xfdTestHunkStructureFlags(0x%08lx, 0x%08lx, %lu, 0x%08lx)\n",
		Self, buffer, length, flags);
	APTR bufstart, bufend;
	WORD num, hunks;
	LONG type, size;

	if (buffer == NULL || length == 0) {
		return XFDERR_NOSOURCE;
	}

	if (READ_ULONG(buffer, 0) != HUNK_HEADER) {
		return XFDERR_NOHUNKHEADER;
	}

	bufstart = buffer;
	bufend = buffer + length;
	num = 0;

	do {
		type = READ_ULONG_INC(buffer) & 0x3fffffff;
		switch (type) {
			case HUNK_CODE:
			case HUNK_DATA:
				num -= 1;
			case HUNK_NAME:
			case HUNK_DEBUG:
				size = READ_ULONG_INC(buffer) << 2;
				buffer += size;
				break;
			case HUNK_BSS:
				buffer += 4;
				num -= 1;
			case HUNK_END:
			case HUNK_BREAK:
				break;
			case HUNK_RELOC32:
			case HUNK_SYMBOL:
				while (TRUE) {
					if (buffer >= bufend || buffer < bufstart) {
						return XFDERR_BUFFERTRUNCATED;
					}
				    size = READ_ULONG_INC(buffer) << 2;
					if (size == 0) {
						break;
					}
					buffer += size + 4;
				}
				break;
			case HUNK_DREL32:
			case HUNK_RELOC32SHORT:
				while (TRUE) {
					if (buffer >= bufend || buffer < bufstart) {
						return XFDERR_BUFFERTRUNCATED;
					}
					size = READ_UWORD_INC(buffer) << 1;
					if (size == 0) {
						break;
					}
					buffer += size + 2;
				}
				if ((bufend - buffer) & 0x2) {
					buffer += 2;
				}
				break;
			case HUNK_HEADER:
				if (READ_ULONG_INC(buffer) != 0) {
					return XFDERR_UNSUPPORTEDHUNK;
				}
				hunks = READ_WORD(buffer, 10) - READ_WORD(buffer, 6) + 1;
				if (hunks <= 0) {
					return XFDERR_BUFFERTRUNCATED;
				}
				num += hunks;
				buffer += 12 + ((ULONG)hunks << 2);
				break;
			case HUNK_OVERLAY:
				if (flags & XFDTHF_NOOVERLAYS) {
					return XFDERR_NOOVERLAYS;
				}
				size = READ_ULONG_INC(buffer) << 2;
				if (size) {
					buffer += size + 4;
				} else if (READ_ULONG_INC(buffer) == 0x3f6) {
					num = 0;
					buffer = bufend;
				}
				break;
			default:
				return XFDERR_UNSUPPORTEDHUNK;
		}
		if (buffer < bufstart || buffer > bufend) {
			return XFDERR_BUFFERTRUNCATED;
		}
	} while (buffer != bufend);

	if (num != 0) {
		return XFDERR_WRONGHUNKAMOUNT;
	}

	return XFDERR_OK;
}

