From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  7-JUN-1989 19:52
To:	MRGATE::"ARISIA::EVERHART"
Subj:	RE:  Getting image data.

Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Wed,  7 JUN 89 15:00:42 PDT
Received: from grouch.JPL.NASA.GOV by KL.SRI.COM with TCP; Wed, 7 Jun 89 14:45:42 PDT
Received: by grouch id <00002D0D101@grouch.JPL.NASA.GOV> ;
       Wed,  7 Jun 89 10:52:24 PST
Date: Wed,  7 Jun 89 10:48:50 PST
From: Peter Scott <PJS@grouch.JPL.NASA.GOV>
Subject: RE:  Getting image data.
To: Joern Yngve Dahl-Stamnes <dahls%vax.elab.unit.uninett@nac.no>
X-Vms-Mail-To: EXOS%"Joern Yngve Dahl-Stamnes <dahls%vax.elab.unit.uninett@nac.no>"
Message-Id: <890607104850.00002D0D101@grouch.JPL.NASA.GOV>
Cc: info-vax@kl.sri.com

This is a code fragment from a program I wrote a long time ago to
scan EXE files.  This part retrieves the link date/time.  The pseudo-VMS
symbolic names are made up.  No flames about coding style please; as I
said, it's an old program.  Also no promises about workability, it's
based mostly on my own analysis of the structure of .EXE files and a
bunch of guesses I made that so far have worked out.

Peter Scott (pjs@grouch.jpl.nasa.gov)

-------------------------------Cut---------------------------------------
main (argc, argv)
int argc;
char *argv[];
{
   short IHD$W_SIZE, IHD$W_ACTIVOFF, IHD$W_SYMDBGOFF, IHD$W_IMGIDOFF;
   $DESCRIPTOR(file_desc,argv[1]);

   file_desc.dsc$w_length = strlen (argv[1]);
   blockopen (&file_desc);
   IHD$W_SIZE = getword();
   IHD$W_ACTIVOFF = getword();
   IHD$W_SYMDBGOFF = getword();
   IHD$W_IMGIDOFF = getword();
   print_link_date (IHD$W_IMGIDOFF);
}

print_link_date (ident_off)
short ident_off;
 {
   struct dsc$descriptor_s time_desc;
   long time[1];
   char timbuf[50];
   long timlen;
   int result;
   char byt;
   int i, len;
   long current_position;
   time_desc.dsc$w_length = 50;
   time_desc.dsc$a_pointer = timbuf;
   time_desc.dsc$b_dtype = DSC$K_DTYPE_T;
   time_desc.dsc$b_class = DSC$K_CLASS_S;
   absmove (ident_off & 0xffff);
/*
    Parse string ident
*/
   byt = getbyte();
   len = byt & 0xff;
   for (i = 1; i <= len; i++) getbyte();
/*
    Skip intervening spaces
*/
   while ((byt = getbyte() & 0xff) == 0) ;
/*
    Parse Version Number
*/
   len = byt & 0xff;
   for (i = 1; i <= len; i++) getbyte();
/*
    Skip intervening spaces
*/
   while ((byt = getbyte() & 0xff) == 0) ;
/*
    Back up to the last longword
*/
   current_position = where_am_i (&0);
   absmove ((current_position >> 2) << 2);
   time[0] = getlong();
   time[1] = getlong();   
   result = sys$asctim (&timlen, &time_desc, &time, 0);
   if (result != 1)
      printf ("Incorrect result from sys$asctim: %d\n", result);
   else
    {
      timbuf[timlen] = '\0';
      printf ("Link Date/Time: %s\n", timbuf);
    }
 }   

absmove (address)
 {
   for_absmove (&address);
 }
-------------------------------Cut---------------------------------------

      SUBROUTINE BLOCKOPEN (FILENAME)
      INTEGER*4 RECORD, OFFSET
      COMMON/BLK/RECORD, OFFSET
      CHARACTER*(*) FILENAME
      RECORD = 0
      OFFSET = 0
      OPEN (UNIT=5, FILE=FILENAME, STATUS='OLD',
     1      ACCESS='DIRECT', RECORDTYPE='FIXED', READONLY)
      RETURN
      END
C
      INTEGER*4 FUNCTION GETBYTE (IDUMMY)
      BYTE RESULT
      INTEGER*4 RECORD, OFFSET, TEMP
      BYTE DUMMY(512)
      COMMON/BLK/RECORD,OFFSET
      IF (OFFSET .EQ. 512) THEN
        RECORD = RECORD + 1
        OFFSET = 0
      ENDIF
C      type *, ' record = ', record, ' offset = ', offset     
      MYREC = RECORD + 1
      READ (5,REC=MYREC) (DUMMY(I), I=1,OFFSET), RESULT
      TEMP = RESULT
      OFFSET = OFFSET + 1
      GETBYTE = JIAND (TEMP, 255)
      RETURN
      END
C

      INTEGER*4 FUNCTION GETWORD (IDUMMY)
      INTEGER*4 RESULT, GETBYTE
      INTEGER*4 RECORD, OFFSET
      COMMON/BLK/RECORD, OFFSET
      RESULT = GETBYTE(0)
C      type *, ' record = ', record, ' offset = ', offset     
      GETWORD = RESULT + GETBYTE(0) * 256
C      type *, ' getword result = ', result
      RETURN
      END
C
      INTEGER*4 FUNCTION GETLONG (IDUMMY)
      INTEGER*4 RESULT, GETWORD
      RESULT = GETWORD(0)
      GETLONG = RESULT + JISHFT(GETWORD(0), 16)
      RETURN
      END
C
      SUBROUTINE FOR_ABSMOVE (ADDR)
      INTEGER*4 ADDR
      INTEGER*4 RECORD, OFFSET
      COMMON/BLK/ RECORD, OFFSET
C      type *,' ABSMOVE: addr = ', addr,
C     1 ' record = ', record, ' offset = ', offset
      OFFSET = JMOD(ADDR, 512)
      RECORD = ADDR / 512
      RETURN
      END
C
      INTEGER*4 FUNCTION WHERE_AM_I (IDUMMMY)
      INTEGER*4 RECORD, OFFSET
      COMMON/BLK/ RECORD, OFFSET
C      type *, ' record = ', record, ' offset = ', offset
      WHERE_AM_I = RECORD * 512 + OFFSET
      RETURN
      END
-------------------------------Cut---------------------------------------


