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

UWORD _xfdMaster_xfdStripHunks(struct xfdMasterIFace *Self, APTR buffer,
	ULONG length, ULONG *result, ULONG flags)
{
	DEBUGF("xfdStripHunks(0x%08lx, 0x%08lx, %lu, 0x%08lx, 0x%08lx)\n",
		Self, buffer, length, result, flags);
	struct xfdMasterBase *libBase = (struct xfdMasterBase *)Self->Data.LibBase;
	struct UtilityIFace *IUtility = libBase->xfdm_IUtility;
	UWORD error;
	APTR bufstart, bufend, bufnext;
	WORD hunks, type;
	LONG size;

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

	error = Self->xfdTestHunkStructureFlags(buffer, length, XFDTHF_NOOVERLAYS);
	if (error != XFDERR_OK) {
		return error;
	}

	bufstart = buffer;
	bufend = buffer + length;
	hunks = READ_WORD(buffer, 18) - READ_WORD(buffer, 14) + 1;
	buffer += 20 + ((ULONG)hunks << 2);

	while (buffer != bufend) {
		type = (WORD)READ_ULONG_INC(buffer);
		switch (type) {
			case HUNK_CODE:
			case HUNK_DATA:
				size = READ_ULONG_INC(buffer) << 2;
				buffer += size;
				break;
			case HUNK_BSS:
				buffer += 4;
				break;
			case HUNK_RELOC32:
				while ((size = READ_ULONG_INC(buffer) << 2)) {
					buffer += size + 4;
				}
				break;
			case HUNK_DREL32:
			case HUNK_RELOC32SHORT:
				while ((size = READ_UWORD_INC(buffer) << 1)) {
					buffer += size + 2;
				}
				if ((bufend - buffer) & 0x2) {
					buffer += 2;
				}
				break;
			case HUNK_NAME:
				if (flags & XFDSHF_NAME) {
					size = READ_ULONG_INC(buffer) << 2;
					bufnext = buffer + size;
					size = bufend - bufnext;
					buffer -= 8;
					IUtility->MoveMem(bufnext, buffer, size);
					bufend = buffer + size;
				} else {
					size = READ_ULONG_INC(buffer) << 2;
					buffer += size;
				}
				break;
			case HUNK_DEBUG:
				if (flags & XFDSHF_DEBUG) {
					bufnext = buffer;
					buffer -= 4;
					size = READ_ULONG_INC(bufnext) << 2;
					bufnext += size;

					size = bufend - bufnext;
					IUtility->MoveMem(bufnext, buffer, size);
					bufend = buffer + size;
				} else {
					size = READ_ULONG_INC(buffer) << 2;
					buffer += size;
				}
				break;
			case HUNK_SYMBOL:
				if (flags & XFDSHF_SYMBOL) {
					bufnext = buffer;
					buffer -= 4;
					while ((size = READ_ULONG_INC(bufnext) << 2)) {
						bufnext += size + 4;
					}

					size = bufend - bufnext;
					IUtility->MoveMem(bufnext, buffer, size);
					bufend = buffer + size;
				} else {
					while ((size = READ_ULONG_INC(buffer) << 2)) {
						buffer += size + 4;
					}
				}
				break;
			case HUNK_END:
				break;
			default:
				return XFDERR_UNSUPPORTEDHUNK;
		}
	}

	*result = bufend - bufstart;
	return XFDERR_OK;
}

