/************************************************************************/
/*                                                                      */
/* ShowHunk.c       ---     shows the Hunkformat of files               */
/*                                                                      */
/*                          All Hunks up to V40 are supported           */
/*                          are recognized.                             */
/*                                                                      */
/* Sorry for the bad C-Style....it's not my mother language:-)          */
/* BTW...if you find some bugs or do some enhancements i would          */
/* like to get the modified source. This program is FREEWARE and        */
/* should never be distributed without the source.                      */
/* Not for commercial use!                                              */
/*                                                                      */
/* I want to thank Randell Jesup for his new hunk definitions!          */
/*                                                                      */
/*----------------------------------------------------------------------*/
/*                                                                      */
/* V1.00 - 06/3/92     "Small C-Hack" (V1.00) by Ralph Schmidt          */
/* V1.01 - 13/3/92     "1.Bug Fix"    (V1.01) by Ralph Schmidt          */
/* V1.02 - 09/3/93     "2.Bug Fix"    (V1.02) by Ralph Schmidt          */
/* V1.03 - 24/11/93    "Enhanced"     (V1.03) by Ralph Schmidt          */
/*                     "Fixed Libparsing problem"                       */
/*                                                                      */
/************************************************************************/

#define HUNK_UNIT	999
#define HUNK_NAME	1000
#define HUNK_CODE	1001
#define HUNK_DATA	1002
#define HUNK_BSS	1003
#define HUNK_RELOC32	1004
#define HUNK_RELOC16	1005
#define HUNK_RELOC8	1006
#define HUNK_ABSRELOC32	HUNK_RELOC32
#define HUNK_ABSRELOC16	1022
#define HUNK_RELRELOC32	1021
#define HUNK_RELRELOC16	HUNK_RELOC16
#define HUNK_RELRELOC8	HUNK_RELOC8
#define HUNK_EXT	1007
#define HUNK_SYMBOL	1008
#define HUNK_DEBUG	1009
#define HUNK_END	1010
#define HUNK_HEADER	1011
#define HUNK_OVERLAY	1013
#define HUNK_BREAK	1014
#define HUNK_DREL32	1015
#define HUNK_DREL16	1016
#define HUNK_DREL8	1017
#define HUNK_LIB	1018
#define HUNK_INDEX	1019
#define HUNK_RELOC32SHORT 1020
#define HUNK_RELOC32SHORT_V37 1015


#define EXT_SYMB	0
#define EXT_DEF		1
#define EXT_ABS		2
#define EXT_RES		3
#define EXT_REF32	129
#define EXT_ABSREF32	EXT_REF32
#define EXT_COMMON	130
#define EXT_ABSCOMMON	EXT_COMMON
#define EXT_RELCOMMON	137
#define EXT_REF16	131
#define EXT_REF8	132
#define EXT_ABSREF16	138
#define EXT_ABSREF8	139
#define EXT_RELREF32	136
#define EXT_RELREF16	EXT_REF16
#define EXT_RELREF8	EXT_REF8
#define EXT_DEXT32	133
#define EXT_DEXT16	134
#define EXT_DEXT8	135


#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <string.h>

const UBYTE Version[] = "$VER: ShowHunk 1.03 ("__DATE__")";

#define BUFFERSIZE      256
#define READLONG	(Status=Read(FileHandle,Buffer,4))
#define READWORD	(Status=Read(FileHandle,Buffer,2))

ULONG	Buffer[BUFFERSIZE+1];
ULONG	StringBuffer[BUFFERSIZE];
char	AttrString[15];
LONG	Status;
BPTR	FileHandle;
BPTR	MyFile;
BOOL	Symbol;
	struct	RDArgs *rdargs=NULL;

void	exit(int);

void EXITUS(void)
{
        if (rdargs)
           FreeArgs(rdargs);
	if (FileHandle)
           Close(FileHandle);
	exit(20);
}

void EXITUS_CTRL(void)
{
        FPuts(MyFile,"CTRL-C...Break\n");
	if (FileHandle)
           Close(FileHandle);
	exit(20);
}

void ReadLong(void)
{
	if (SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
           EXITUS_CTRL();
	if ( READLONG !=4 )
	{
		if (Status == -1) FPuts(MyFile,"Error: Read Error\n");
		else FPuts(MyFile,"Error: Unexpected File End\n");
		EXITUS();
	}
}

void ReadWord(void)
{
	if (SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
           EXITUS_CTRL();
	if ( READWORD !=2 )
	{
		if (Status == -1) FPuts(MyFile,"Error: Read Error\n");
		else FPuts(MyFile,"Error: Unexpected File End\n");
		EXITUS();
	}
}

void SeekLong(void)
{
	ReadLong();
	if ( (Status=Seek(FileHandle,Buffer[0]<<2,OFFSET_CURRENT)) == -1)
	{
		FPuts(MyFile,"Error: Read Error\n");
		EXITUS();
	}

}	

void SeekReloc(char * RELOC_Type)
{
	for(;;)
	{
		ReadLong();
		if ( !Buffer[0]) break;
		Buffer[1]=Buffer[0];
		ReadLong();
		Buffer[2]=Buffer[0];
		if ( (Status=Seek(FileHandle,Buffer[1]<<2,OFFSET_CURRENT)) == -1)
		{
			FPuts(MyFile,"Error: Read Error\n");
			EXITUS();
		}
		FPrintf(MyFile,"%s (Hunk %ld) %ld Bytes\n",RELOC_Type,Buffer[2],Buffer[1]<<2);
	}
}

void SeekRelocShort(char * RELOC_Type)
{
int	Bytes;
	Bytes=0;
	for(;;)
	{
		ReadWord();
		Buffer[1]=Buffer[0] >> 16;
		if ( Buffer[1] == NULL ) break;
		ReadWord();
		Buffer[2]=Buffer[0] >> 16;
		if ( (Status=Seek(FileHandle,(Buffer[1]<<1) ,OFFSET_CURRENT)) == -1)
		{
			FPuts(MyFile,"Error: Read Error\n");
			EXITUS();
		}
		FPrintf(MyFile,"%s (Hunk %ld) %ld Bytes\n",RELOC_Type,Buffer[2],Buffer[1]<<2);

                Bytes+=Buffer[2]*2;
	}
        Bytes+=2;	/*ReadWord();==0 */
        if (Bytes & 2)
           ReadWord();
}

void ReadString(void)
{
ULONG	length;

	ReadLong();
	length=Buffer[0]<<2;
	if ( length > BUFFERSIZE)
	{
		FPuts(MyFile,"Error: Name too long\n");
		EXITUS();
	}
	if (Status=Read(FileHandle,StringBuffer,length) != length)
	{
		if (Status == -1) FPuts(MyFile,"Error: Read Error\n");
		else FPuts(MyFile,"Error: Unexpected File End\n");
		EXITUS();
	}
	((char *) StringBuffer)[length]='\0';
}

void ShowSymbolUnit_Def(char * EXT_Type)
{
	ReadLong();
	FPrintf(MyFile,"  EXT_%s\n",EXT_Type);
	FPrintf(MyFile,"      %s = 0x%lx\n",(char *) StringBuffer,Buffer[0]);
}

void ShowSymbolUnit_Ref(char * EXT_Type)
{
	ULONG	i,j;
	ReadLong();
	i=Buffer[0];
	for (j=0;j<i;j++)
	{
		ReadLong();
		FPrintf(MyFile,"  EXT_%s\n",EXT_Type);
		FPrintf(MyFile,"      %s = 0x%lx\n",(char *) StringBuffer,Buffer[0]);
	}
}

void ShowSymbolUnit_Common(char * EXT_Type)
{
	ULONG	Size,i,j;
	ReadLong();
	Size=Buffer[0];
	ReadLong();
	i=Buffer[0];
	for (j=0;j<i;j++)
	{
		ReadLong();
		FPrintf(MyFile,"  EXT_%s 0x%ld Bytes\n",EXT_Type,Size);
		FPrintf(MyFile,"      %s = 0x%lx\n",(char *) StringBuffer,Buffer[0]);
	}
}



int ReadSymbolDataUnit(void)
{
ULONG	length,type;

	ReadLong();
	if ( ! Buffer[0]) return 0;
	length = (Buffer[0] & 0xffffff) << 2;
	type = (Buffer[0] & 0xff000000) >> 24;
	if ( length > BUFFERSIZE)
	{
		FPuts(MyFile,"Error: Name too long\n");
		EXITUS();
	}
	Buffer[length >> 2]=0;
	if (Status=Read(FileHandle,StringBuffer,length) != length)
	{
		if (Status == -1) FPuts(MyFile,"Error: Read Error\n");
		else FPuts(MyFile,"Error: Unexpected File End\n");
		EXITUS();
	}
	((char *) StringBuffer)[length]='\0';
	switch ( type )
	{
	case	EXT_DEF:
		ShowSymbolUnit_Def("DEF");
		break;
	case	EXT_ABS:
		ShowSymbolUnit_Def("ABS");
		break;
	case	EXT_RES:
		ShowSymbolUnit_Def("RES");
		break;
	case	EXT_ABSREF32:
		ShowSymbolUnit_Ref("ABSREF32");
		break;
	case	EXT_ABSREF16:
		ShowSymbolUnit_Ref("ABSREF16");
		break;
	case	EXT_ABSREF8:
		ShowSymbolUnit_Ref("ABSREF8");
		break;
	case	EXT_RELREF32:
		ShowSymbolUnit_Ref("RELREF32");
		break;
	case	EXT_RELREF16:
		ShowSymbolUnit_Ref("RELREF16");
		break;
	case	EXT_RELREF8:
		ShowSymbolUnit_Ref("RELREF8");
		break;
	case	EXT_DEXT32:
		ShowSymbolUnit_Ref("DEXT32");
		break;
	case	EXT_DEXT16:
		ShowSymbolUnit_Ref("DEXT16");
		break;
	case	EXT_DEXT8:
		ShowSymbolUnit_Ref("DEXT8");
		break;
	case	EXT_ABSCOMMON:
		ShowSymbolUnit_Common("ABSCOMMON");
		break;
	case	EXT_RELCOMMON:
		ShowSymbolUnit_Common("RELCOMMON");
		break;
	default:
		FPrintf(MyFile,"Error: Unknow EXT Type 0x%lx\n",type);
		EXITUS();
		break;
	}
	return	1;


}

char*	GetMemType(ULONG MemType)

{
	switch ( MemType )
	{
	case	0x00000000:
		return ("MEMF_PUBLIC");
		break;

	case	0x20000000:
		return ("ADVISORY");
		break;

	case	0x40000000:
		return ("MEMF_CHIP");
		break;

	case	0x80000000:
		return ("MEMF_FAST");
		break;

	case	0xc0000000:
		Buffer[1]=Buffer[0];
		ReadLong();
		FPrintf(MyFile,AttrString,"0x%lx\0",Buffer[0]);
		Buffer[0]=Buffer[1];
		return (AttrString);
		break;
	}
}



int	ReadModule(ULONG	FileType,
                   BOOL		HunkEndFinished)
{
	BYTE	Flag;
	char	*MemString;
        BOOL	LastHunkIsHUNKEND=FALSE;

	Flag=-1;
	while ( Flag )
	{
		if ( READLONG !=4 )
		{
                  if (LastHunkIsHUNKEND)
                     return(0);

                  FPuts(MyFile,"Error: Read Error\n");
                  EXITUS();
		}
                LastHunkIsHUNKEND	=	FALSE;
		switch ( Buffer[0] & 0x3fffffff)
		{
	
			case	HUNK_END:
                                LastHunkIsHUNKEND	=	TRUE;
				FPuts(MyFile,"HUNK_END\n");
                                if (HunkEndFinished)
                                   return(TRUE);
				break;

			case	HUNK_NAME:
				ReadString();
				FPrintf(MyFile,"HUNK_NAME `%s'\n",(char *) StringBuffer);
				break;

			case	HUNK_CODE:
				MemString=GetMemType( Buffer[0] & 0xe0000000);
				SeekLong();
				FPrintf(MyFile,"HUNK_CODE  %ld Bytes (Memory Type = %s)\n",(Buffer[0] & 0x1fffffff) <<2 ,MemString);
				break;

			case	HUNK_DATA:
				MemString=GetMemType( Buffer[0] & 0xe0000000);
				SeekLong();
				FPrintf(MyFile,"HUNK_DATA  %ld Bytes (Memory Type = %s)\n",(Buffer[0] & 0x1fffffff) <<2 ,MemString);
				break;

			case	HUNK_BSS:
				MemString=GetMemType( Buffer[0] & 0xe0000000);
				ReadLong();
				FPrintf(MyFile,"HUNK_BSS  %ld Bytes (Memory Type = %s)\n",(Buffer[0] & 0x1fffffff) <<2 ,MemString);
				break;
	
			case	HUNK_DEBUG:
				SeekLong();
				FPrintf(MyFile,"HUNK_DEBUG   %ld Bytes\n",(Buffer[0] & 0x1fffffff) <<2 );
				break;
	
	
			case	HUNK_SYMBOL:
				FPuts(MyFile,"HUNK_SYMBOL\n");
				for(;;)
				{
					ReadString();
					if (Buffer[0] == 0) break;
					ReadLong();
                                        if (Symbol)
					   FPrintf(MyFile,"  %s = 0x%lx\n",StringBuffer,Buffer[0]);
				}
				break;

			case	HUNK_EXT:
				FPuts(MyFile,"HUNK_EXT\n");
				for(;;)
				{
					Status=ReadSymbolDataUnit();
					if (!Status) break;
				}
				break;


			case	HUNK_RELOC32SHORT:
				SeekRelocShort("HUNK_RELOC32SHORT");
				break;

			case	HUNK_ABSRELOC32:
				SeekReloc("HUNK_ABSRELOC32");
				break;

			case	HUNK_ABSRELOC16:
				SeekReloc("HUNK_ABSRELOC16");
				break;
	
			case	HUNK_RELRELOC32:
				SeekReloc("HUNK_RELRELOC32");
				break;

			case	HUNK_RELRELOC16:
				SeekReloc("HUNK_RELRELOC16");
				break;

			case	HUNK_RELRELOC8:
				SeekReloc("HUNK_RELRELOC8");
				break;
	
/*			case	HUNK_RELOC32SHORT_V37:*/
			case	HUNK_DREL32:
				if ( FileType == HUNK_HEADER )
                                   SeekRelocShort("HUNK_RELOC32SHORT");
				else
                                   SeekReloc("HUNK_DREL32");
				break;

			case	HUNK_DREL16:
				SeekReloc("HUNK_DREL16");
				break;
			case	HUNK_DREL8:
				SeekReloc("HUNK_DREL8");
				break;

			default:
				Flag=0;
				if ( (Status=Seek(FileHandle,-4,OFFSET_CURRENT)) == -1)
				{
					FPuts(MyFile,"Error: Read Error\n");
					EXITUS();
				}

/*
				FPrintf(MyFile,"Error: Unknow Hunk 0x%lx\n",Buffer[0]);
				EXITUS();
*/
				break;
		}
	
	}
	return -1;
}

LONG	*MyArgs[5];

char	*ArgumentString = "File,Symbols/S";


void main(int argc, char **argv)
{
	ULONG	Start,End,Count,i,Condition;
	char	*MemString;

        MyFile	=	Output();
	
	FPuts(MyFile,"\x9b""0;33;40m""ShowHunk V1.01 \x9b""0;31;40m""© Ralph Schmidt 1992\n");
	FPuts(MyFile,"Email: laire@uni-paderborn.de\n");

        if (!(rdargs=ReadArgs(ArgumentString,(LONG*) &MyArgs[0],NULL)))
        {
          puts("Commandline Error\n");
          return;
        }

        Symbol=(BOOL) MyArgs[1];

        FileHandle  = Open((STRPTR) MyArgs[0], MODE_OLDFILE);
        if ( ! FileHandle )
	{
		FPrintf(MyFile,"Cannot open %s\n",argv[1]);
                EXITUS();
        }

	while( READLONG )
	{
		switch ( Buffer[0] & 0x3fffffff )
		{
		case	HUNK_HEADER:
	                FPuts(MyFile,"HUNK_HEADER\n");
			while( READLONG && Buffer[0])
			{
				ReadString();
				FPrintf(MyFile,"Resident Library: %s\n",(char *) StringBuffer);
			}
			ReadLong();
			Count=Buffer[0];
			ReadLong();
			Start=Buffer[0];
			ReadLong();
			End=Buffer[0];
			FPrintf(MyFile,"%ld Hunks from %ld to %ld\n",Count,Start,End);
			for(i=Start;i<=End;i++)
			{
				ReadLong();
				MemString=GetMemType( Buffer[0] & 0xe0000000);
				FPrintf(MyFile,"Hunk %ld = %ld Bytes (Memory Type = %s)\n",i,(Buffer[0] & 0x1fffffff) <<2 ,(char *) MemString);
			}
			FPuts(MyFile,"\n");
			for(i=Start;i<=End;i++)
			{
				ReadModule(HUNK_HEADER,TRUE);
				FPuts(MyFile,"\n");
			}
			break;

		case	HUNK_UNIT:
			ReadString();
			FPrintf(MyFile,"HUNK_UNIT `%s'\n",(char *) StringBuffer);
			Condition=-1;
/*			while(Condition)*/
			{
				Condition=ReadModule(HUNK_UNIT,FALSE);
			}
			break;

		case	HUNK_LIB:
			SeekLong();
			FPrintf(MyFile,"HUNK_LIB   %ld Bytes\n",Buffer[0]<<2);
			ReadLong();
			if (Buffer[0] != HUNK_INDEX)
			{
				FPrintf(MyFile,"Error: Unknow Hunk 0x%lx\n",Buffer[0]);
				EXITUS();
				break;
			}
			else
			{
			SeekLong();
			FPrintf(MyFile,"HUNK_INDEX   %ld Bytes\n",Buffer[0]<<2);
			break;
			}

		default:
			FPrintf(MyFile,"Error: Unknow Hunk 0x%lx\n",Buffer[0]);
			EXITUS();
			break;

		}
        }
        FreeArgs(rdargs);
	Close(FileHandle);
}
