
/*
 * [!BGN - MACHINE GENERATED - DO NOT EDIT THIS HEADER]
 *
 * Program   : HunkReader (Executable/Object file hunk viewer)
 * Version   : 1.4
 * File      : Work:Source/!WIP/HunkReader/HR.c
 * Author    : Andrew Bell
 * Copyright : Copyright © 1999 Andrew Bell, All rights reserved.
 * Created   : Saturday 15-Nov-97 08:30:00
 * Modified  : Friday 27-Aug-99 01:06:09
 * Comment   : 
 *
 * (Generated with StampSource 1.2 by Andrew Bell)
 *
 * [!END - MACHINE GENERATED - DO NOT EDIT THIS HEADER]
 *
 */

/* Created: Sat/15/Nov/1997 */

#define MONTH   "August"
#define YEAR    "1997-99"
#define EMAIL "andrew.ab2000@bigfoot.com"
#define WWW "http://www.homeusers.prestel.co.uk/ab2000"

/* Maybe one day I'll make this code totally portable. */

/* Includes */

#include <HunkReader_rev.h>

#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/doshunks.h>
#include <dos/stdio.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>

#pragma header

/* Defines */

#define MASK ( HUNKF_ADVISORY | HUNKF_CHIP | HUNKF_FAST )

#define TEMPLATE "FILE/A,DSYM/S,DREL/S,DEXT/S,STATS/S"

enum
{
  ARG_FILE = 0,     /* Incoming file */
  ARG_DSYM,         /* Display symbol tables */
  ARG_DREL,         /* Display reloc tables */
  ARG_DEXT,         /* Display ext hunks */
  ARG_STATS,        /* Display stats */
  ARG_AMT           /* Array size */
};

/* Prototypes */

void DoErr( void );
void DumpHunks( BPTR );
ULONG MoveForward( BPTR, LONG );
BOOL TestAbort( void );
void BuildFlagString( ULONG, UBYTE *);
LONG MyRead( BPTR FH, APTR Buf, ULONG Length);
UBYTE *Plural( ULONG, UBYTE *, UBYTE *);

void DoHUNK_EXT( BPTR FH );
void DoUNKNOWN( BPTR FH );
void DoHUNK_HEADER( BPTR FH );
void DoHUNK_CODE( BPTR FH );
void DoHUNK_DATA( BPTR FH );
void DoHUNK_BSS( BPTR FH );
void DoHUNK_END( BPTR FH );
void DoHUNK_OVERLAY( BPTR FH);
void DoHUNK_BREAK( BPTR FH );
void DoHUNK_DEBUG( BPTR FH );
void DoHUNK_SYMBOL( BPTR FH );
void DoHUNK_RELOC32( BPTR FH );
void DoHUNK_DREL32( BPTR FH );
void DoHUNK_RELOC32SHORT( BPTR FH );
void DoHUNK_DREL32( BPTR FH );
void DoHUNK_UNIT( BPTR FH );
void DoHUNK_NAME( BPTR FH );
void DoHUNK_EXT( BPTR FH );

/* We let the startup code/linker deal with these */

extern struct ExecBase *SysBase;
extern struct Library *DOSBase;


/* Varables and data */

static UBYTE VerTag[] = VERSTAG;

ULONG aa[ARG_AMT];
ULONG stream[99];
UBYTE TempBuffer[256+4];

/***********************************************************************/

ULONG main( void )
{
  struct RDArgs *ArgInfo;

  if (SysBase->LibNode.lib_Version < 37)
  {
    #define BADOSTXT "Sorry, this program requires at least OS 37+\n"
    
    Write(Output(), BADOSTXT, sizeof(BADOSTXT) );
    return RETURN_FAIL;
  }
  
  if (!(SysBase->AttnFlags & AFF_68020))
  {
    #define BADCPUTXT "Sorry, this program requires at least a MC68020\n"

    Write(Output(), BADOSTXT, sizeof(BADOSTXT) );
    return RETURN_FAIL;   
  }
  
  if (ArgInfo = (struct RDArgs *) ReadArgs(TEMPLATE, (LONG *) &aa, NULL))
  {
    BPTR InLock;

    Printf(VERS " (" DATE "),\n"
          "Copyright © " YEAR " Andrew Bell, All rights reserved.\n"
          "email: " EMAIL "\n"
          "  web: " WWW "\n");

    if (InLock = Lock( (UBYTE *) aa[ARG_FILE], SHARED_LOCK))
    {
      struct FileInfoBlock *FIB;

      if (FIB = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, NULL))
      {
        if (Examine(InLock, FIB))
        {
          if (FIB->fib_DirEntryType < 0)
          {
            if (FIB->fib_Size)
            {
              BPTR InHandle;

              Printf("\nViewing %s's hunks structure, length %lu bytes.\n\n",
                &FIB->fib_FileName, FIB->fib_Size);

              if (InHandle = Open( (UBYTE *) aa[ARG_FILE], MODE_OLDFILE))
              {
                if (SysBase->LibNode.lib_Version >= 40)
                {
                  SetVBuf(InHandle, NULL, BUF_FULL, (64*1024));
                }
                                
                DumpHunks(InHandle);
                Close(InHandle);

              }   /* Open */
              else DoErr();

            }   /* NULL length check */
            else Printf("Subject file is empty!\n");

          }   /* File/dir check */
          else Printf("I need a file, not a directory!\n");

        }   /* Examine() */
        else DoErr();

        FreeDosObject(DOS_FIB, FIB);

      } /* AllocDosObject() */
      else DoErr();

      UnLock(InLock);

    } /* Lock() */
    else DoErr();

    FreeArgs(ArgInfo);

  } /* ReadArgs() */
  else DoErr();

  return RETURN_OK;

} /* _main() */

/***********************************************************************/

void DoErr( void )
{
  PrintFault(IoErr(), "Error ");
}

/***********************************************************************/

/* Global variables */

BOOL Flag_EOF    = FALSE; /* Will equal TRUE if EOF (All OK) */
BOOL Flag_UEOF   = FALSE; /* Will equal TRUE if unexpected EOF  */
BOOL Flag_Error  = FALSE; /* Will equal TRUE if error happened */
BOOL Flag_BadId  = FALSE; /* Unknown hunk pop up it's ugly head */
BOOL Flag_Break  = FALSE; /* Will equal TRUE if Ctrl+C is hit */
BOOL Flag_NotSup = FALSE; /* Hunk type is not supported */

BOOL FFlag_Exe   = FALSE; /* Will equal TRUE if HUNK_HEADER was encontered */
BOOL FFlag_Obj   = FALSE; /* Will equal TRUE if HUNK_UNIT was encontered */

ULONG HunkOrgId  = NULL;  /* Unaltered ID, contains length + bits */
ULONG HunkId     = NULL;  /* Altered ID, contains length only */
ULONG HunkFlags  = NULL;  /* Altered ID, contains bits only */
ULONG HunkOffset = NULL;
ULONG HunkCnt    = NULL;

/* Zero all of these */

ULONG Cnt_Header       = 0; /* */
ULONG Cnt_Code         = 0; /* */
ULONG Cnt_Data         = 0; /* */
ULONG Cnt_BSS          = 0; /* */
ULONG Cnt_End          = 0; /* */
ULONG Cnt_Overlay      = 0; /* */
ULONG Cnt_Break        = 0; /* */
ULONG Cnt_Symbol       = 0; /* */
ULONG Cnt_SymbolEnt    = 0; /* */
ULONG Cnt_Debug        = 0; /* */
ULONG Cnt_Reloc32      = 0; /* */
ULONG Cnt_Reloc32Ent   = 0; /* Number of entries */
ULONG Cnt_Reloc32Short = 0; /* */
ULONG Cnt_Reloc32SEnt  = 0; /* Number of entries */
ULONG Cnt_DRel32       = 0; /* */
ULONG Cnt_DRel32Ent    = 0; /* */

ULONG Cnt_HunksChip    = 0; /* */
ULONG Cnt_HunksFast    = 0; /* */
ULONG Cnt_HunksPub     = 0; /* */
ULONG Cnt_HunksAdv     = 0; /* */

ULONG TOTALAlloc = 0;

void DumpHunks( BPTR FH )
{
  LONG ReadResult;

  do
  {
    HunkOffset = Seek(FH, 0, OFFSET_CURRENT);

    if (HunkOffset == -1)
    {
      Flag_Error = TRUE; break;
    }

    if ((ReadResult = Read(FH, &HunkOrgId, 4)) == -1)
    {
      Flag_Error = TRUE; break;
    }

    if (ReadResult == NULL)
    {
      Flag_EOF=TRUE; break;
    }

    HunkId = HunkOrgId;

    HunkFlags = HunkId & MASK;  /* extract flag bits from id */
    HunkId &= ~MASK;        /* remove flag bits from id */

    switch(HunkId)
    {
      case HUNK_HEADER: DoHUNK_HEADER(FH); break;
      case HUNK_CODE: DoHUNK_CODE(FH); break;
      case HUNK_DATA: DoHUNK_DATA(FH); break;
      case HUNK_BSS: DoHUNK_BSS(FH); break;
      case HUNK_END: DoHUNK_END(FH); break;
      case HUNK_RELOC32: DoHUNK_RELOC32(FH); break;
      case HUNK_RELOC32SHORT: DoHUNK_RELOC32SHORT(FH); break;
      case HUNK_DREL32: DoHUNK_DREL32(FH); break;

      case HUNK_OVERLAY: DoHUNK_OVERLAY(FH); break;
      case HUNK_BREAK: DoHUNK_BREAK(FH); break;
      case HUNK_DEBUG: DoHUNK_DEBUG(FH); break;
      case HUNK_SYMBOL: DoHUNK_SYMBOL(FH); break;

      case HUNK_UNIT: DoHUNK_UNIT(FH); break;
      case HUNK_NAME: DoHUNK_NAME(FH); break;
      case HUNK_EXT: DoHUNK_EXT(FH); break;

      default: DoUNKNOWN(FH); break;
    }

  TestAbort();

  }
  while(    (Flag_EOF == FALSE)
      &&  (Flag_UEOF == FALSE)
      &&  (Flag_Error == FALSE)
      &&  (Flag_BadId == FALSE)
      &&  (Flag_Break == FALSE)
      &&  (Flag_NotSup == FALSE) );

  Printf("\n");

  if (Flag_EOF)
  {
    Printf("\t\tEnd of file\n\n");

    if (aa[ARG_STATS])
    {
      /* This test does not show all hunks! */

      Printf("    Object Type: %s\n"
          "      Amt Hunks: %lu\n"
          "    Hunk_Header: %lu\n"
          "      Hunk_Code: %lu\n"
          "      Hunk_Data: %lu\n"
          "       Hunk_BSS: %lu\n"
          "       Hunk_End: %lu\n"
          "   Hunk_Overlay: %lu\n"
          "     Hunk_Break: %lu\n"
          "    Hunk_Symbol: %lu (total entries: %lu)\n"
          "     Hunk_Debug: %lu\n"
          "   Hunk_Reloc32: %lu (total entries: %lu, %lu bytes)\n"
          " Hunk_Reloc32Sh: %lu (total entries: %lu, %lu bytes)\n"
          "    Hunk_DRel32: %lu (total entries: %lu, %lu bytes)\n"

          "   Hunks > Chip: %lu\n"
          "   Hunks > Fast: %lu\n"
          " Hunks > Public: %lu\n"
          " Advisory Hunks: %lu\n"
          "\n"
          " Amount of memory required to load program, approx: %lu (exe only)\n"
          "\n",
        
      (ULONG) (FFlag_Exe ? "Command file" : "Linkable object file"),
      HunkCnt,

      Cnt_Header,
      Cnt_Code,
      Cnt_Data,
      Cnt_BSS,
      Cnt_End,
      Cnt_Overlay,
      Cnt_Break,
      Cnt_Symbol,
      Cnt_SymbolEnt,
      Cnt_Debug,

      Cnt_Reloc32,
      Cnt_Reloc32Ent,
      Cnt_Reloc32Ent << 2,

      Cnt_Reloc32Short,
      Cnt_Reloc32SEnt,
      Cnt_Reloc32SEnt << 2, /* Use real bytes here */

      Cnt_DRel32,
      Cnt_DRel32Ent,
      Cnt_DRel32Ent << 2,

      Cnt_HunksChip,
      Cnt_HunksFast,
      Cnt_HunksPub,
      Cnt_HunksAdv,
      TOTALAlloc );
    }

  }
  else if (Flag_UEOF)
    Printf("\t\tUnexpected end of file, bad file structure!\n\n");
  else if (Flag_Error)
    DoErr();
  else if (Flag_BadId)
    Printf("\t\tEncountered an unknown hunk type!\n");
  else if (Flag_NotSup)
    Printf("\t\tEncountered an unsupported hunk type!\n");
}

/***********************************************************************/

void DoHUNK_HEADER( BPTR FH )
{
  ULONG HunkATInfo[4];    /* Hunk Allocation Table Info */
  ULONG HunkASize;
  ULONG HunkCnt;
  ULONG HunkRange;
  ULONG AllocFlags;

  Cnt_Header++;

  FFlag_Exe = TRUE;

  Printf("\n\tOffset: 0x%08lx - 0x%08lx - HUNK_HEADER\n",
    HunkOffset, HunkOrgId);

  if (MyRead(FH, &HunkATInfo, 4*4)) return; /* Read 4 LONGs */

  Printf("\t\tAmt of hunks in alloc table: %lu (%lu to %lu)\n",
    HunkATInfo[1], /* Amt  */
    HunkATInfo[2], /* Rng1 */
    HunkATInfo[3]  /* Rng2 */ );

  HunkRange=(HunkATInfo[3]-HunkATInfo[2])+1; /* (Rng2-Rng1) + 1 */

  for (HunkCnt = 0; HunkCnt < HunkRange ; HunkCnt++)
  {
    if (MyRead(FH, &HunkASize, 4)) return;

    AllocFlags = HunkASize & MASK;    /* Keep alloc flags */

    BuildFlagString(HunkASize, TempBuffer);

    if (AllocFlags & HUNKF_ADVISORY) Cnt_HunksAdv++;
    else if (AllocFlags & HUNKF_FAST) Cnt_HunksFast++;
    else if (AllocFlags & HUNKF_CHIP) Cnt_HunksChip++;
    else Cnt_HunksPub++;

    HunkASize &= ~MASK; /* remove flags */

    TOTALAlloc += (HunkASize << 2);

    Printf("\t\tHunk %3lu, length %9lu %s\n",
      HunkCnt, HunkASize * 4, &TempBuffer );

    if (TestAbort()) return;
  }
}

/***********************************************************************/

void DoHUNK_CODE( BPTR FH )
{
  ULONG HunkLength;

  Cnt_Code++;

  Printf("Hnk #%lu\tOffset: 0x%08lx - 0x%08lx - HUNK_CODE\n",
    HunkCnt++, HunkOffset, HunkOrgId );

  if (MyRead(FH, &HunkLength, 4)) return;
  
  HunkLength *= 4;

  BuildFlagString(HunkOrgId, TempBuffer);

  Printf("\t\tRead length - %lu %s\n",
    HunkLength, (ULONG)TempBuffer );

  if (MoveForward(FH, HunkLength)) return;
}

/***********************************************************************/

void DoHUNK_DATA( BPTR FH )
{
  ULONG HunkLength;

  Cnt_Data++;

  Printf("Hnk #%lu\tOffset: 0x%08lx - 0x%08lx - HUNK_DATA\n",
    HunkCnt++, HunkOffset, HunkOrgId, &stream);

  if (MyRead(FH, &HunkLength, 4)) return; HunkLength *= 4;

  BuildFlagString(HunkOrgId, TempBuffer);

  Printf("\t\tRead length - %lu %s\n",
    HunkLength, TempBuffer );

  if (MoveForward(FH, HunkLength)) return;
}

/***********************************************************************/

void DoHUNK_BSS( BPTR FH )
{
  ULONG HunkLength;

  Cnt_BSS++;

  Printf("Hnk #%lu\tOffset: 0x%08lx - 0x%08lx - HUNK_BSS\n",
    HunkCnt++, HunkOffset, HunkOrgId );

  if (MyRead(FH, &HunkLength, 4)) return; HunkLength*=4;

  BuildFlagString(HunkOrgId, TempBuffer);

  Printf("\t\tAllocation length - %lu %s\n",
    HunkLength, TempBuffer );
}

/***********************************************************************/

void DoHUNK_END( BPTR FH )
{
  Cnt_End++;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_END\n",
    HunkOffset, HunkOrgId );
}

/***********************************************************************/

void DoHUNK_OVERLAY( BPTR FH )
{
  ULONG HunkLength;

  Cnt_Overlay++;

  Printf("Hnk #%lu\tOffset: 0x%08lx - 0x%08lx - HUNK_OVERLAY\n",
    HunkCnt++, HunkOffset, HunkOrgId );

  if (MyRead(FH, &HunkLength, 4)) return; HunkLength*=4;

  BuildFlagString(HunkOrgId, TempBuffer);

  Printf("\t\tLength - %lu %s\n",
    HunkLength, TempBuffer );

  if (MoveForward(FH, HunkLength+4)) return;
}

/***********************************************************************/

void DoHUNK_BREAK( BPTR FH )
{
  Cnt_Break++;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_BREAK\n",
    HunkOffset, HunkOrgId );
}

/***********************************************************************/

void DoHUNK_DEBUG( BPTR FH )
{
  ULONG HunkLength;

  Cnt_Debug++;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_DEBUG\n",
    HunkOffset, HunkOrgId, &stream);

  if (MyRead(FH, &HunkLength, 4)) return; HunkLength *= 4;

  BuildFlagString(HunkOrgId, TempBuffer);

  Printf("\t\tLength - %lu\n", HunkLength, TempBuffer );

  if (MoveForward(FH, HunkLength)) return;
}

/***********************************************************************/
/* Length, <........>, Offset */

/* TODO: Merge this hunk with HUNK_EXT, because both are identical */

void DoHUNK_SYMBOL( BPTR FH )
{
  APTR SymBuf;
  ULONG SymCnt,SymLen,SymOffset;
  ULONG R1,R2;

  Cnt_Symbol++;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_SYMBOL\n",
    HunkOffset, HunkOrgId );

  for(SymCnt = 0;;)
  {
    if (MyRead(FH, &SymLen, 4)) return;
    if (SymLen == NULL) break;

    if (aa[ARG_DSYM])
    {
      if (SymBuf = (APTR)AllocVec( (SymLen + 1) * 4, MEMF_CLEAR))
      {
        R1 = MyRead(FH, SymBuf, SymLen*4);      /* Read symbol */
        R2 = MyRead(FH, &SymOffset, 4);       /* Read offset */

        Printf( "\t\t[%-30.30s] at 0x%08lx (%lu)\n",
          SymBuf, SymOffset, SymOffset );

        FreeVec(SymBuf);

        if (R1 || R2) return;
      }
      else
        if (MoveForward(FH, (SymLen+1)*4)) return;  /* Skip symbol + offset */
    }
    else
      if (MoveForward(FH, (SymLen+1)*4)) return;  /* Skip symbol + offset */

    if (TestAbort()) return;

    SymCnt++;
  }

  Printf("\t\tContains %lu symbol entr%s\n",
    SymCnt, Plural( SymCnt, "y", "ies" ));

  Cnt_SymbolEnt += SymCnt;
}

/***********************************************************************/
/* Amount, Hunk, <........> */

void DoHUNK_RELOC32( BPTR FH )
{
  ULONG RelocAmt,RelocHunk;
  Cnt_Reloc32++;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_RELOC32\n",
    HunkOffset, HunkOrgId );

  for(;;)
  {
    if (MyRead(FH, &RelocAmt, 4)) return;
    if (RelocAmt == NULL) break;          /* End of table? */
    if (MyRead(FH, &RelocHunk, 4)) return;

    Cnt_Reloc32Ent+=RelocAmt;

    Printf("\t\t%lu reference%s to hunk #%lu\n",
          RelocAmt, Plural(RelocAmt, "", "s"), RelocHunk );

    if (aa[ARG_DREL])
    {
      while (RelocAmt--)
      {
        ULONG Rel32;
        
        if (MyRead(FH, &Rel32, 4)) return;

        Printf("\t\tRelocate offset 0x%08lx using hunk base #%lu\n",
          Rel32, RelocHunk );

        if (TestAbort()) return;
      }
    }
    else if (MoveForward(FH, RelocAmt*4)) return;
  }
}

/***********************************************************************/

void DoHUNK_DREL32( BPTR FH )
{
  UWORD RelocAmt, RelocHunk, RelocEntry;
  ULONG POF;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_DREL32\n",
    HunkOffset, HunkOrgId );

  Cnt_DRel32++;

  for(;;)
  {   
    if (MyRead(FH, &RelocAmt, 2)) return;
    if (RelocAmt == NULL) break;        /* End of table? */
    if (MyRead(FH, &RelocHunk, 2)) return;

    Cnt_DRel32Ent += RelocAmt;

    Printf("\t\t%lu reference%s to hunk #%lu\n",
      (ULONG) RelocAmt,
      Plural(RelocAmt, "", "s"),
      (ULONG) RelocHunk );

    stream[1] = RelocHunk;

    if (aa[ARG_DREL])
    {
      while (RelocAmt--)
      {
        if (MyRead(FH, &RelocEntry, 2)) return;

        Printf("\t\tRelocate offset 0x%04lx using hunk base #%lu\n",
          (ULONG) RelocEntry, (ULONG) RelocHunk );

        if (TestAbort()) return;
      }
    }
    else if (MoveForward(FH, RelocAmt*2)) return;
  }

  POF = Seek(FH, 0, OFFSET_CURRENT);

  /* If we are not on a LONG boundary then align... */

  if ((POF >> 2) << 2 != POF)
    if (MoveForward(FH, 2)) return;   /* Alignment fix */

}

/***********************************************************************/

void DoHUNK_RELOC32SHORT( BPTR FH )
{
  UWORD RelocAmt,RelocHunk;
  UWORD RelocEntry;
  ULONG POF;

  Cnt_Reloc32Short++;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_RELOC32SHORT\n",
    (ULONG) HunkOffset, (ULONG) HunkOrgId );

  for(;;)
  {
    if (MyRead(FH, &RelocAmt, 2)) return;
    if (RelocAmt == NULL) break;        /* End of table? */
    if (MyRead(FH, &RelocHunk, 2)) return;

    Cnt_Reloc32SEnt += RelocAmt;

    Printf("\t\t%lu reference%s to hunk #%lu\n",
      (ULONG)RelocAmt,
      Plural(RelocAmt, "", "s"),
      (ULONG)RelocHunk );

    stream[1] = RelocHunk;

    if (aa[ARG_DREL])
    {
      while (RelocAmt--)
      {
        if (MyRead(FH, &RelocEntry, 2)) return;

        Printf("\t\tRelocate offset 0x%04lx using hunk base #%lu\n",
          (ULONG) RelocEntry, (ULONG) RelocHunk );

        if (TestAbort()) return;
      }
    }
    else if (MoveForward(FH, RelocAmt * 2)) return;
  }

  POF = Seek(FH, 0, OFFSET_CURRENT);

  /* If we are not on a LONG boundary then align... */

  if ((POF >> 2) << 2 != POF)
    if (MoveForward(FH, 2)) return;   /* Alignment fix */
}

/***********************************************************************/

void DoHUNK_UNIT( BPTR FH )
{
  ULONG NameLen;
  APTR NameBuf;

  FFlag_Obj = TRUE;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_UNIT\n",
    HunkOffset, HunkOrgId );

  if (MyRead(FH, &NameLen, 4)) return;    /* Get length of name */

  if ( NameBuf = (APTR) AllocVec( (NameLen + 1) * 4, MEMF_CLEAR) )
  {
    if (MyRead(FH, NameBuf, NameLen*4)) return;
    Printf("\t\tUnit name: %.40s\n", NameBuf);
    FreeVec(NameBuf);
  }
  else if (MoveForward(FH, NameLen*4)) return;
}

/***********************************************************************/

void DoHUNK_NAME( BPTR FH )
{
  ULONG NameLen;
  APTR NameBuf;

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_NAME\n",
    HunkOffset, HunkOrgId );

  if (MyRead(FH, &NameLen, 4)) return;    /* Get length of name */

  if (NameBuf = (APTR) AllocVec((NameLen+1)*4, MEMF_CLEAR))
  {
    if (MyRead(FH, NameBuf, NameLen*4)) return;

    Printf("\t\tHunk name: %.40s\n", NameBuf);

    FreeVec(NameBuf);
  }
  else if (MoveForward(FH, NameLen*4)) return;
}

/***********************************************************************/

#define EXT_NEWCOMMON 4  /* 5? */

void DoHUNK_EXT( BPTR FH )
{
  APTR  ExtTypeStr;
  UBYTE ExtType;
  UWORD ExtLen;
  ULONG ExtOffset;
  ULONG RefCnt;
  ULONG ComSize;
  APTR  ExtSymBuf;

  ULONG R1,R2,R3;   /* Results, Used for IO error checking */

  Printf("\tOffset: 0x%08lx - 0x%08lx - HUNK_EXT\n",
    HunkOffset, HunkOrgId );

  for (;;)
  {
    R1 = MyRead(FH, &ExtType, 1);   /* Read ext type */
    R2 = MoveForward(FH, 1);      /* Alignment fix */
    R3 = MyRead(FH, &ExtLen, 2);    /* Read ext length */

    if (R1 || R2 || R3) return;

    if (ExtLen == NULL) break;  /* End of ext hunk? */

    switch(ExtType)
    {
      case EXT_SYMB: ExtTypeStr = "EXT_SYMB"; goto XDEF;
      case EXT_DEF:  ExtTypeStr = "EXT_DEF";  goto XDEF;
      case EXT_ABS:  ExtTypeStr = "EXT_ABS";  goto XDEF;
      case EXT_RES:  ExtTypeStr = "EXT_RES";

        XDEF:   /* sym def, XDEF */

        if (ExtSymBuf = (APTR)AllocVec((ExtLen+2)*4, MEMF_CLEAR))
        {
          R1 = MyRead(FH, ExtSymBuf, (ExtLen*4));   /* Read ext symbol */
          R2 = MyRead(FH, &ExtOffset, 4);       /* Read common size */

          if (aa[ARG_DEXT])
          {
            Printf("\t\t%-14.14s [%-30.30s] = 0x%08lx\n",         
              (ULONG) ExtTypeStr, (ULONG) ExtSymBuf, ExtOffset );
          }
          FreeVec(ExtSymBuf);
          if (R1 || R2) return;
        }
        else
        {
          R1 = MyRead(FH, &ExtOffset, 4); /* Read common size */
          R2 = MoveForward(FH, ExtLen*4); /* Skip ext symbol */
          if (R1 || R2) return;
        }
        break;

      case EXT_COMMON: ExtTypeStr = "EXT_COMMON";
        COMMONREF:  /* common ref */

        if (ExtSymBuf = (APTR) AllocVec((ExtLen+2)*4, MEMF_CLEAR))
        {
          R1 = MyRead(FH, ExtSymBuf ,(ExtLen*4)+4);   /* Read ext symbol to buffer */
          R2 = MyRead(FH, &ComSize, 4);         /* Read common size */
          R3 = MyRead(FH, &RefCnt, 4);            /* Read ref count */
          R3 = MoveForward(FH, RefCnt*4);         /* Skip reference entries */

          if (aa[ARG_DEXT]) /* Does use want to see ext info? */
          {
            Printf("\t\t%-14.14s [%-30.30s] cs: %lu ref%s: %lu\n",
              (ULONG) ExtTypeStr,
              (ULONG) ExtSymBuf,
              (ULONG) Plural(RefCnt, "", "s"),
              ComSize,
              RefCnt ); /* Check text bounds */
          }
          FreeVec(ExtSymBuf);
          if (R1 || R2 || R3) return;
        }
        else  /* If unable to alloc sym buf then Seek() */
        {
          R1 = MoveForward(FH, (ExtLen*4)+8); /* Skip symbol + common size*/
          R2 = MoveForward(FH, 4);        /* Skip ref count */
          R3 = MoveForward(FH, RefCnt*4);   /* Skip refs */
          if (R1 || R2 || R3) return;
        }
        break;

      case EXT_REF32:     ExtTypeStr = "EXT_REF32";     goto XREF;
      case EXT_REF16:     ExtTypeStr = "EXT_REF16";     goto XREF;
      case EXT_REF8:      ExtTypeStr = "EXT_REF8";      goto XREF;
      case EXT_DEXT32:    ExtTypeStr = "EXT_DEXT32";    goto XREF;
      case EXT_DEXT16:    ExtTypeStr = "EXT_DEXT16";    goto XREF;
      case EXT_DEXT8:     ExtTypeStr = "EXT_DEXT8";     goto XREF;
      case EXT_RELREF32:  ExtTypeStr = "EXT_RELREF32";  goto XREF;
      case EXT_RELCOMMON: ExtTypeStr = "EXT_RELCOMMON"; goto XREF;
      case EXT_ABSREF16:  ExtTypeStr = "EXT_ABSREF16";  goto XREF;
      case EXT_ABSREF8:   ExtTypeStr = "EXT_ABSREF8"; 

        XREF: /* sym ref, XREF */

        if (ExtSymBuf = (APTR) AllocVec((ExtLen*4)+4, MEMF_CLEAR))
        {
          R1 = MyRead(FH, ExtSymBuf, ExtLen*4); /* Read symbol */
          R2 = MyRead(FH, &RefCnt, 4);        /* Read ref count */
          R3 = MoveForward(FH, RefCnt*4);     /* Skip references */

          if (aa[ARG_DEXT])
          {
            Printf("\t\t%-14.14s [%-30.30s] ref%s: %lu\n",
              (ULONG) ExtTypeStr,
              (ULONG) ExtSymBuf,
              (ULONG) Plural(RefCnt, "", "s"),
              RefCnt ); /* Check text bounds */
          }
          FreeVec(ExtSymBuf);
          
          if (R1 || R2 || R3) return;
        }
        else
        {
          R1 = MoveForward(FH, ExtLen*4);   /* Skip symbol */
          R2 = MyRead(FH, &RefCnt, 4);      /* Get ref count */
          R3 = MoveForward(FH, RefCnt*4);   /* Skip references */
          if (R1 || R2 || R3) return;
        }
        break;
    }
    if (TestAbort()) break;
  }

}

/***********************************************************************/

void DoUNKNOWN( BPTR FH )
{
  Printf("\tOffset: 0x%08lx - 0x%08lx - Unknown hunk!!!\n",
    HunkOffset, HunkOrgId );
    
  Flag_BadId = TRUE;
}

/***********************************************************************/

ULONG MoveForward( BPTR FH, LONG Length)
{
  LONG Result = Seek(FH, Length, OFFSET_CURRENT);

  if (Result == -1)
  {
    Flag_Error = TRUE;
    return(-1);
  }
  else
    return(NULL);
}

/***********************************************************************/

BOOL TestAbort( void )
{
  if (CheckSignal(SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
  {
    Printf("\n***Break:\n\n");
    Flag_Break = TRUE;
    return(TRUE);
  }
  else
    return(FALSE);
}

/***********************************************************************/

void BuildFlagString( ULONG Flags, UBYTE *Buf)
{
  /* move.b d0,(a3)+ \n rts */
  
  UWORD putChProc[] = { 0x16c0, 0x4e75 };

  stream[0] = (ULONG)"";
  stream[1] = (ULONG)"";
  stream[2] = (ULONG)"";

  Flags &= MASK;        /* remove unwanted size */

  if (Flags & HUNKF_CHIP)
    stream[0] = (ULONG)"[Load to Chip] ";
  if (Flags & HUNKF_FAST)
    stream[1] = (ULONG)"[Load to Fast] ";
  if (Flags & HUNKF_ADVISORY)
    stream[2] = (ULONG)"[Advisory]";

  /* Flush CPU here? */

  RawDoFmt("%s%s%s", &stream, (void *) &putChProc, Buf);
}

/***********************************************************************/

LONG MyRead( BPTR FH, APTR Buf, ULONG Length)
{
  LONG Result;
  
  if (!Length) return 0;  /* If user passes NULL, then return */

  Result = FRead(FH, Buf, Length, 1);

  if (Result != 1)
  {
    Flag_UEOF = TRUE;
    return -1;  /* Not OK */
  }
  else
  {
    return 0;   /* OK */
  }
}

/***********************************************************************/

UBYTE *Plural( ULONG Val, UBYTE *One, UBYTE *Many)
{
  if (Val == 1) return(One); else return(Many);
}



