###############################################################################
# package........ CoffFile
# created........ 03/29/2001
# last updated .. 04/17/2001
# CopyRight...... (c) Texas Instruments 2001, All Rights Reserved
#------------------------------------------------------------------------------
# /*===========================================================================*/
# /* This software is provided under the following                             */
# /* License Agreement:                                                        */
# /*===========================================================================*/
# /* THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR               */
# /* REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,                    */
# /* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS              */
# /* FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR                    */
# /* COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.                */
# /* TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET                */
# /* POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY                       */
# /* INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR                */
# /* YOUR USE OF THE PROGRAM.                                                  */
# /*                                                                           */
# /* IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,               */
# /* CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY                 */
# /* THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED                */
# /* OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT                */
# /* OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.               */
# /* EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF                 */
# /* REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS               */
# /* OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF                 */
# /* USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S                    */
# /* AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF                */
# /* YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS                       */
# /* (U.S.$500).                                                               */
# /*                                                                           */
# /* Unless otherwise stated, the Program written and copyrighted              */
# /* by Texas Instruments is distributed as "freeware".  You may,              */
# /* only under TI's copyright in the Program, use and modify the              */
# /* Program without any charge or restriction.  You may                       */
# /* distribute to third parties, provided that you transfer a                 */
# /* copy of this license to the third party and the third party               */
# /* agrees to these terms by its first use of the Program. You                */
# /* must reproduce the copyright notice and any other legend of               */
# /* ownership on each copy or partial copy, of the Program.                   */
# /*                                                                           */
# /* You acknowledge and agree that the Program contains                       */
# /* copyrighted material, trade secrets and other TI proprietary              */
# /* information and is protected by copyright laws,                           */
# /* international copyright treaties, and trade secret laws, as               */
# /* well as other intellectual property laws.  To protect TI's                */
# /* rights in the Program, you agree not to decompile, reverse                */
# /* engineer, disassemble or otherwise translate any object code              */
# /* versions of the Program to a human-readable form.  You agree              */
# /* that in no event will you alter, remove or destroy any                    */
# /* copyright notice included in the Program.  TI reserves all                */
# /* rights not specifically granted under this license. Except                */
# /* as specifically provided herein, nothing in this agreement                */
# /* shall be construed as conferring by implication, estoppel,                */
# /* or otherwise, upon you, any license or other right under any              */
# /* TI patents, copyrights or trade secrets.                                  */
# /*                                                                           */
# /* You may not use the Program in non-TI devices.                            */
# /*===========================================================================*/
# This module parses a COFF file created by Texas Instruments TMS DSP
# code generation tools and offers a set of easy to use methods for obtaining
# information from the COFF file. This information includes header info.,
# symbol table, section data, etc.
#
# Mehtods:
#  $coffFileRef = new("coffFileName")
#                 delete()
#  $headerRef   = header()
#  $sectionRef  = secRewind()
#  $sectionRef  = secSeek(position)
#  $sectionRef  = secFind("sectionName")
#  $sectionRef  = secEnum()
#  $dataRef     = secRead()
#  $symRef      = symRewind()
#  $symRef      = symSeek(position)
#  $symRef      = symFind("symbolName")
#  $symRef      = symEnum()
#                 _dump(mode)
#
#  headerRef is a reference to a has with the following keys:
#    fullName*
#    fileEndian*
#    numBootSections*
#    versionId
#    numSectionHeaders
#    dateStamp
#    symbolTableAddr
#    numEntriesSymbolTable
#    numBytesOptHeader
#    flags
#    magicNumber
#    optMagicNumber
#    optVersionStamp
#    optExeSize
#    optInitSize
#    optUninitSize
#    optEntryPoint
#    optExeAddr
#    optInitAddr
#
#  sectionRef is a reference to a hash with the following keys:
#    bootFlag*
#    name
#    phyAddr
#    virAddr
#    byteSize
#    wordSize
#    dataPtr
#    reloPtr
#    linePtr
#    numRelos
#    numLines
#    flags
#    reserved
#    memPage
#
#  symRef is a reference to a hash with the following keys:
#    name
#    value
#    secNum
#    type
#    class
#    auxNum
#
#  * Most of the hash keys are named directly after the field in the COFF file
#    but the ones marked with an '*' were invented here to give additional info.
#    Please see the 'TMS320C6000 Assembly Language Tools User's Guide' (SPRUG186G)
#    for details of the fields.
#
#------------------------------------------------------------------------------
# EXAMPLES:
#
#    
#  #########################
#  # dump header information
#  #########################
#  use CoffFile;
#  $cf = new CoffFile("akvp3000.out");
#  $headerRef = $cf->header();
#  foreach $key (keys(%{$headerRef})) {
#    printf("header{$key} = %s\n", $headerRef->{$key});
#  }
#  printf("\n");
#
#  #########################
#  # dump section header
#  #########################
#  use CoffFile;
#  $cf = new CoffFile("akvp3000.out");
#  $secRef = $cf->secFind(".cinit");
#  if (defined $secRef) {
#    foreach $key (keys(%{$secRef})) {
#      printf("section{$key} = %s\n", $secRef->{$key});
#    }
#  }
#  printf("\n");
#
#  #########################
#  # dump raw section data
#  #########################
#  use CoffFile;
#  $cf = new CoffFile("akvp3000.out");
#  $secRef = $cf->secFind(".cinit");
#  if (defined $secRef) {
#    $dataRef = $cf->secRead();
#    foreach $x (@{$dataRef}) {
#      printf("0x%08X ",$x);
#    }
#    printf("\n");
#  }
#  printf("\n");
#
#  ####################
#  # dump symbol table
#  ####################
#  use CoffFile;
#  $cf = new CoffFile("akvp3000.out");
#  $symRef = $cf->symRewind();
#  while (defined $symRef) {
#    if ($symRef->{"name"} ne "") {
#      printf("0x%08X %s\n",$symRef->{"value"},$symRef->{"name"});
#    }
#    $symRef = $cf->symEnum();
#  }
#  printf("\n");
#
#
#  ##############################
#  # dump section header table
#  ##############################
#  use CoffFile;
#  $cf = new CoffFile("akvp3000.out");
#  $secRef = $cf->secRewind();
#  printf("phyAddr    byteSize   flags      name\n");
#  while (defined $secRef) {
#    printf("0x%08X ",$secRef->{"phyAddr"});
#    printf("0x%08X ",$secRef->{"byteSize"});
#    printf("0x%08X ",$secRef->{"flags"});
#    printf("%s\n",$secRef->{"name"});
#    $secRef = $cf->secEnum();
#  }
#  printf("\n");
#
###############################################################################

package CoffFile;
require 5.000;
use FileHandle;
use Symbol;
use File::Basename;
use BinFile;

my $COFF0 = 0x00c0;
my $COFF1 = 0x00c1;
my $COFF2 = 0x00c2;
my ($ThisCoff);

###############################################################################

sub _MSG {
  my ($msg) = shift(@_);
  if (0) {
    STDERR->printf("MSG: %s\n",$msg);
  }
}

###############################################################################

#set some constants
my  $STYP_REG     = 0x00000000;
my  $STYP_DESCT   = 0x00000001;
my  $STYP_NOLOAD  = 0x00000002;
my  $STYP_GROUP   = 0x00000004;
my  $STYP_PAD     = 0x00000008;
my  $STYP_COPY    = 0x00000010;
my  $STYP_TEXT    = 0x00000020;
my  $STYP_DATA    = 0x00000040;
my  $STYP_BSS     = 0x00000080;
my  $STYP_CLINK   = 0x00004000;


###############################################################################
#  $coffFileRef = new("coffFileName")
###############################################################################
sub new {

  my ($class,$fullName) = @_;
  my ($this) = {};
  my ($name,$path,$suffix,$binFile);
  bless($this, $class);

  _MSG("new($class,$fullName)");

  $this->{"private"}  = {};
  $this->{"header"}   = {};
  $this->{"sections"} = [];
  $this->{"symbols"}  = [];

  ($name,$path,$suffix) = fileparse($fullName,'\..*');
  $binFile = BinFile->new($fullName);

  $this->{"header"}{"fullName"}    = $fullName;
  $this->{"private"}{"name"}       = $name;
  $this->{"private"}{"path"}       = $path;
  $this->{"private"}{"suffix"}     = $suffix;
  $this->{"private"}{"binFile"}    = $binFile;
  $this->{"private"}{"curSecNum"}  = 0;
  $this->{"private"}{"curSymNum"}  = 0;
  $this->{"private"}{"symParsed"}  = 0;

  _parseTheCoffFile($this);

  return $this;
}


###############################################################################
#  DESTROY
###############################################################################
sub DESTROY {

  my ($this) = shift(@_);
  my ($fullName) = $this->{"header"}{"fullName"};
  
  _MSG("DESTROY($fullName)");

  $this->{"private"}{"binFile"}->DESTROY();
}

###############################################################################
#  delete()
###############################################################################
sub delete {
  undef $_[1];
}

###############################################################################
#  $header = header();
###############################################################################
sub header {

  my ($this) = shift(@_);

  _MSG("header()");

  return $this->{"header"};
}


###############################################################################
#  $section = secRewind()
###############################################################################
sub secRewind {

  my ($this) = shift(@_);
  my ($secRef) = undef;

  _MSG("secRewind()");

  $this->{"private"}{"curSecNum"} = 0;
  $secRef =  $this->{"sections"}[$this->{"private"}{"curSecNum"}];
  return $secRef;
}


###############################################################################
#  $section = secSeek(position)
###############################################################################
sub secSeek {

  my ($this) = shift(@_);
  my ($position) = shift(@_);
  my ($secRef) = undef;

  _MSG("secSeek($position)");

  if (($position >= 0) && ($position < $this->{"header"}{"numSectionHeaders"})) {
    $this->{"private"}{"curSecNum"} = $position;
    $secRef =  $this->{"sections"}[$this->{"private"}{"curSecNum"}];
  }
  return $secRef;
}


###############################################################################
#  $section = secFind("sectionName")
###############################################################################
sub secFind {

  my ($this) = shift(@_);
  my ($secName) = shift(@_);
  my ($secRef) = undef;
  my ($pos);

  _MSG("secFind($secName)");
  
  for ($pos=0; $pos<$this->{"header"}{"numSectionHeaders"}; $pos++) {
    if ($secName eq $this->{"sections"}[$pos]{"name"}) {
      $this->{"private"}{"curSecNum"} = $pos;
      $secRef =  $this->{"sections"}[$this->{"private"}{"curSecNum"}];
      last;
    }
  }
  return $secRef;
}


###############################################################################
#  $section = secEnum()
###############################################################################
sub secEnum {

  my ($this) = shift(@_);
  my ($secRef) = undef;
  my ($position) = $this->{"private"}{"curSecNum"} + 1;

  _MSG("secEnum()");
  
  if (($position >= 0) && ($position < $this->{"header"}{"numSectionHeaders"})) {
    $this->{"private"}{"curSecNum"} = $position;
    $secRef =  $this->{"sections"}[$this->{"private"}{"curSecNum"}];
  }
  return $secRef;
}


###############################################################################
#  $section = secRead()
###############################################################################
sub secRead {

  my ($this) = shift(@_);
  my ($sectionNum) = shift(@_);
  my ($dataRef) = undef;
  my ($x,$cf,$section,$bigEndian,$coffFlags);

  _MSG("secRead()");

  $coffFlags = $this->{"header"}{"flags"};
  $section = $this->{"sections"}[$sectionNum];
  $cf = $this->{"private"}{"binFile"}; 
  $cf->seek($section->{"dataPtr"});

  if ($coffFlags & 0x0200) {

    # DSP target is big endian
    $cf->endian("little");
    for ($x=0; $x<($section->{"wordSize"}); $x++) {
      $dataRef->[$x] = $cf->read32();    
    }

  } elsif ($coffFlags & 0x0100) {

    # DSP target is little endian
    $cf->endian("big");
    for ($x=0; $x<($section->{"wordSize"}); $x++) {
      $dataRef->[$x] = $cf->read32();    
    }

  }


  #put the endian back to what it should be
  $cf->endian($this->{"header"}{"fileEndian"});

  return $dataRef;
}


###############################################################################
#  $sym = symRewind()
###############################################################################
sub symRewind {

  my ($this) = shift(@_);
  my ($symRef) = undef;

  _MSG("symRewind()");

  if ($this->{"private"}{"symParsed"} == 0) {_parseSymbolTable($this);}

  $this->{"private"}{"curSymNum"} = 0;
  $symRef =  $this->{"symbols"}[$this->{"private"}{"curSymNum"}];
  return $symRef;
}


###############################################################################
#  $sym = symSeek(position)
###############################################################################
sub symSeek {

  my ($this) = shift(@_);
  my ($position) = shift(@_);
  my ($symRef) = undef;

  _MSG("symSeek()");

  if ($this->{"private"}{"symParsed"} == 0) {_parseSymbolTable($this);}

  if (($position >= 0) && ($position < $this->{"header"}{"numEntriesSymbolTable"})) {
    $this->{"private"}{"curSymNum"} = $position;
    $symRef =  $this->{"symbols"}[$this->{"private"}{"curSymNum"}];
  }

  return $symRef;
}


###############################################################################
#  $sym = symFind("symbolName")
###############################################################################
sub symFind {

  my ($this) = shift(@_);
  my ($symName) = shift(@_);
  my ($symRef) = undef;
  my ($pos);

  _MSG("symFind($symName)");

  if ($this->{"private"}{"symParsed"} == 0) {_parseSymbolTable($this);}
  
  for ($pos=0; $pos<$this->{"header"}{"numEntriesSymbolTable"}; $pos++) {
    if ($symName eq $this->{"symbols"}[$pos]{"name"}) {
      $this->{"private"}{"curSymNum"} = $pos;
      $symRef =  $this->{"symbols"}[$this->{"private"}{"curSymNum"}];
      last;
    }
  }
  return $symRef;
}


###############################################################################
#  $sym = symEnum()
###############################################################################
sub symEnum {

  my ($this) = shift(@_);
  my ($symRef) = undef;
  my ($position) = $this->{"private"}{"curSymNum"} + 1;

  _MSG("symEnum()");

  if ($this->{"private"}{"symParsed"} == 0) {_parseSymbolTable($this);}

  if (($position >= 0) && ($position < $this->{"header"}{"numEntriesSymbolTable"})) {
    $this->{"private"}{"curSymNum"} = $position;
    $symRef =  $this->{"symbols"}[$this->{"private"}{"curSymNum"}];
  }

  return $symRef;
}


###############################################################################
#  _dump()
###############################################################################
sub _dump {

  my ($this) = shift(@_);
  my (%private, %header, @sections);
  my ($key, $x, $y);

  _MSG("_dump");

  $this->symRewind();
  %private  = %{$this->{"private"}};
  %header   = %{$this->{"header"}};
  @sections = @{$this->{"sections"}};
  @symbols  = @{$this->{"symbols"}};

  for $key (keys(%private)) {
    printf("  private{\"%s\"} = %s\n",$key,$private{$key});
  }

  for $key (keys(%header)) {
    printf("  header{\"%s\"} = %s\n",$key,$header{$key});
  }

  $y = 0;
  foreach $x (@sections) {
    %section = %{$x};
    for $key (keys(%section)) {
      printf("  section[%d]{\"%s\"} = %s\n",$y,$key,$section{$key});
    }
    $y++;
  }

  $y = 0;
  foreach $x (@symbols) {
    %symbol = %{$x};
    for $key (keys(%symbol)) {
      printf("  symbol[%d]{\"%s\"} = %s\n",$y,$key,$symbol{$key});
    }
    $y++;
  }

}


###############################################################################
#  _parseTheCoffFile($this);
###############################################################################
sub _parseTheCoffFile {
  
  my ($this) = shift(@_);
  my ($cf) = $this->{"private"}{"binFile"};
  my ($x0,$x1,$mn,$mnStr,$endian,$secNum,$flags,$symNum);
  my ($numBytesOptHeader, $numBytesHeader, $numBytesSecHdr);

  ################################################################
  # determine the COFF file endianess by checking the magic number
  ################################################################
  $cf->seek(20); $x0 = $cf->read8();
  $cf->seek(21); $x1 = $cf->read8();
  $mn = ($x0 << 8) | $x1;
  $mnStr = sprintf("%04X",$mn);
  if ($mn == 0x9900) {
    $endian = "big";
  } elsif ($mn == 0x0099) {
    $endian = "little";
  } else  {
    die "Invalid magic number 0x$mnStr!";
  }
  #printf STDERR ("%s is in %s endian file format\n",$this->{"header"}{"fullName"},$endian);
  $this->{"header"}{"fileEndian"} = $endian;
  $cf->endian($endian); 


  ##################################################
  # read the file header
  ##################################################
  $cf->seek(0);
   
   $ThisCoff = $cf->read16();

   if ($ThisCoff == 0x0099) {
      $ThisCoff = $COFF0;
   }

   my $versionString = sprintf("0x%04x", $ThisCoff);

  $this->{"header"}{"versionId"}              = $ThisCoff;   ### $cf->read16();
  $this->{"header"}{"numSectionHeaders"}      = $cf->read16();
  $this->{"header"}{"dateStamp"}              = $cf->read32();
  $this->{"header"}{"symbolTableAddr"}        = $cf->read32();
  $this->{"header"}{"numEntriesSymbolTable"}  = $cf->read32();
  $this->{"header"}{"numBytesOptHeader"}      = $cf->read16();
  $this->{"header"}{"flags"}                  = $cf->read16();
  
  if ($ThisCoff != $COFF0) {
    $this->{"header"}{"magicNumber"}          = $cf->read16();
  }
  
  $this->{"header"}{"numBootSections"}        = 0;
  
  if ($ThisCoff == $COFF0) {
     $numBytesHeader = 20;
  } else {
     $numBytesHeader    = 22;
  }
  $numBytesOptHeader = $this->{"header"}{"numBytesOptHeader"};

  ##################################################
  # read the optional file header
  ##################################################
  if ($this->{"header"}{"numBytesOptHeader"} != 0) {
    $cf->seek($numBytesHeader);
    $this->{"header"}{"optMagicNumber"}       = $cf->read16();
    $this->{"header"}{"optVersionStamp"}      = $cf->read16();
    $this->{"header"}{"optExeSize"}           = $cf->read32();
    $this->{"header"}{"optInitSize"}          = $cf->read32();
    $this->{"header"}{"optUninitSize"}        = $cf->read32();
    $this->{"header"}{"optEntryPoint"}        = $cf->read32();
    $this->{"header"}{"optExeAddr"}           = $cf->read32();
    $this->{"header"}{"optInitAddr"}          = $cf->read32();
  }

 
  if ($ThisCoff == $COFF2) {
     $numBytesSecHdr = 48;
  } else {
     $numBytesSecHdr = 40;
  }
  ##################################################
  # read the section headers
  ##################################################
  for ($secNum = 0; $secNum < $this->{"header"}{"numSectionHeaders"}; $secNum++) {
    $this->{"sections"}[$secNum] = {};
    $cf->seek(($numBytesSecHdr*$secNum)+ $numBytesHeader + $numBytesOptHeader);
    $this->{"sections"}[$secNum]{"name"}         = _getName($this);
    $cf->seek(($numBytesSecHdr*$secNum) + $numBytesHeader + $numBytesOptHeader + 8);
    $this->{"sections"}[$secNum]{"phyAddr"}      = $cf->read32(); #1
    $this->{"sections"}[$secNum]{"virAddr"}      = $cf->read32(); #2
    $byteSize                                    = $cf->read32(); #3
    $wordSize =  (($byteSize+3) >> 2);
    $this->{"sections"}[$secNum]{"byteSize"}     = $byteSize;
    $this->{"sections"}[$secNum]{"wordSize"}     = $wordSize;
    $this->{"sections"}[$secNum]{"dataPtr"}      = $cf->read32(); #4
    $this->{"sections"}[$secNum]{"reloPtr"}      = $cf->read32(); #5
    $this->{"sections"}[$secNum]{"linePtr"}      = $cf->read32(); #6

    if ($ThisCoff == $COFF2) {
       $this->{"sections"}[$secNum]{"numRelos"}     = $cf->read32();
       $this->{"sections"}[$secNum]{"numLines"}     = $cf->read32();
       $this->{"sections"}[$secNum]{"flags"}        = $cf->read32();
       $this->{"sections"}[$secNum]{"reserved"}     = $cf->read16();
       $this->{"sections"}[$secNum]{"memPage"}      = $cf->read16();
    } else {
       $this->{"sections"}[$secNum]{"numRelos"}     = $cf->read16();
       $this->{"sections"}[$secNum]{"numLines"}     = $cf->read16();
       $this->{"sections"}[$secNum]{"flags"}        = $cf->read16();
       $this->{"sections"}[$secNum]{"reserved"}     = $cf->read8();
       $this->{"sections"}[$secNum]{"memPage"}      = $cf->read8();
    }


    ##################################################
    # check to see if this section is bootable
    ##################################################
    $flags = $this->{"sections"}[$secNum]{"flags"};
    $this->{"sections"}[$secNum]{"bootFlag"} = 0;
    if (($flags & ($STYP_TEXT|$STYP_DATA)) != 0) {
      if (($flags & $STYP_COPY) == 0) {
        if ($this->{"sections"}[$secNum]{"byteSize"} != 0) {
          $this->{"header"}{"numBootSections"}++;
          $this->{"sections"}[$secNum]{"bootFlag"} = 1;
        }
      }
    }
  }
}


###############################################################################
#  _parseSymbolTable($this);
###############################################################################
sub _parseSymbolTable {
  
  my ($this) = shift(@_);
  my ($cf) = $this->{"private"}{"binFile"};
  my ($symNum);

  ##################################################
  # read the symbol table
  ##################################################
  for ($symNum = 0; $symNum < $this->{"header"}{"numEntriesSymbolTable"}; $symNum++) {
    $this->{"symbols"}[$symNum] = {};
    $cf->seek($this->{"header"}{"symbolTableAddr"} + 18*$symNum);
    $this->{"symbols"}[$symNum]{"name"}   = _getName($this);
    $cf->seek($this->{"header"}{"symbolTableAddr"} + 18*$symNum+8);
    $this->{"symbols"}[$symNum]{"value"}  = $cf->read32();
    $this->{"symbols"}[$symNum]{"secNum"} = $cf->read16();
    $this->{"symbols"}[$symNum]{"type"}   = $cf->read16();
    $this->{"symbols"}[$symNum]{"class"}  = $cf->read8();
    $this->{"symbols"}[$symNum]{"auxNum"} = $cf->read8();
  }

  $this->{"private"}{"symParsed"} = 1;
}


###############################################################################
# $name = _getName($this)
###############################################################################
sub _getName {

  #This subroutine reads an ASCII string name from the COFF file
  #It takes into account if the string is contained within the 8 char
  #header field or a pointer into the string table.

  my ($this) = shift(@_);
  my ($cf) = $this->{"private"}{"binFile"};
  my ($position) = $cf->tell();
  my ($int0,$int1,$i,$c,$name,$pos,$stringTableAddr);

  $name = "";

  $int0 = $cf->read32();
  $int1 = $cf->read32();

  $cf->seek($position);

  if ($int0 == 0x00000000) {
    #the name is stored in the string table
    $stringTableAddr = $this->{"header"}{"symbolTableAddr"} + (18 * $this->{"header"}{"numEntriesSymbolTable"});
    $cf->seek($int1 + $stringTableAddr);
    $c = chr($cf->read8());
    while ($c ne chr(0)) {
      $name = $name.$c;
      $c = chr($cf->read8());
    }
  } else {
    #the name is stored in-place (8 or less charaters)
    $i=0; $c = chr($cf->read8());
    while (($c ne chr(0)) && ($i < 8)) {
      $name = $name.$c;
      $i++; $c = chr($cf->read8());
    }
  }

  return $name;
}

###############################################################################

return 1;  #the package needs to return a 1 to denote success

###############################################################################
# end of CoffFile.pm
###############################################################################


