
/***************************************************************************
**
**    $Header:   D:/EPSLDV1/SRC/LOG/LDRSRV1.CPP   1.8   20 Jun 1996 09:30:04   ZJRD  $
**
**    $Log:   D:/EPSLDV1/SRC/LOG/LDRSRV1.CPP  $
** 
**    Rev 1.8   20 Jun 1996 09:30:04   ZJRD
** EasyPack/SLD Version 1.20a
** 
**    Rev 1.6   10 Jun 1996 10:24:42   ZJRD
** EasyPack/SLD Version 1.20
** 
**    Rev 1.4   29 May 1996 09:37:12   ZJRD
** No change.
** 
**    Rev 1.3   16 May 1996 09:01:50   ZJRD
** No change.
** 
**    Rev 1.2   10 May 1996 09:16:06   ZJRD
** No change.
** 
**    Rev 1.1   02 May 1996 10:30:26   ZJRD
** EasyPack/SLD Version 1.92
** 
**    Rev 1.14   18 Apr 1996 12:55:34   Shirley
** No change.
** 
**    Rev 1.13   12 Apr 1996 10:34:34   Shirley
** EasyPack/SLD Version 1.90
** 
**    Rev 1.11   15 Feb 1996 08:49:02   Shirley
** No change.
** 
**    Rev 1.10   12 Feb 1996 14:04:30   Shirley
** No change.
** 
**    Rev 1.9   06 Feb 1996 15:31:04   Shirley
** No change.
** 
**    Rev 1.8   06 Feb 1996 13:45:56   Shirley
** No change.
** 
**    Rev 1.7   01 Feb 1996 10:19:18   Shirley
** No change.
** 
**    Rev 1.6   26 Jan 1996 09:14:30   Shirley
** No change.
** 
**    Rev 1.5   25 Jan 1996 13:14:24   Shirley
** No change.
** 
**    Rev 1.4   24 Jan 1996 10:33:32   Shirley
** No change.
** 
**    Rev 1.3   23 Jan 1996 11:22:24   Shirley
** No change.
** 
**    Rev 1.2   18 Jan 1996 10:13:20   Shirley
** No change.
** 
**    Rev 1.1   15 Jan 1996 16:15:50   Shirley
** No change.
** 
**    Rev 1.0   04 Jan 1996 11:13:38   Shirley
** Initial revision.
** 
****************************************************************************/

/****************************************************************************
**
**  Name:  LDRSRV1.CPP
**
**  Description:
**      Entry points for IEEE695 Loader.
**
**  Status:  CODED
**
**    Rev 1.0   1 Dec. 1995 8:30:00am   Gates Hua, Jamoon Chow
** Initial revision.
**
**  Copyright (C) 1995 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#include "stdafx.h"
//#include <ctype.h>
//#include <io.h>
//#include <sys\timeb.h>
//#include <time.h>
//#include <fcntl.h>
//#include <sys\stat.h>

#include "symblsvr.h"
#include "ldr.h"           
#include "ldr695.h"
#include "uicom.h"
#include "abibase.h"

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern U32 start , end;
extern U8 LineNumInfo[16] , SymDefInfo[51] , OldKey;
extern struct BlockBlock far *curBlock ;
extern SYM_DESCRIPTOR curModDesc;
//extern int nErrorNum;

extern U32 startAddr_ASW[8] ;
extern U8 curByte;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
extern STATUS AbiFill(ADDR addr1, ADDR addr2,char* pchBuff,UINT uPatternLen);


/*****************************************************************************
**
**  Is695Command
**       return: 1 - a 695 command
**               2 - may be  a command
**               0 - not a command
**              -1 - error
**
*****************************************************************************/
int LoaderServer::Is695Command() 
{
	U8 data[4];
    if ( PeekByte(&curByte) != GOOD ) return FAILURE;
    if ( curByte < 0xE0 ) return 0;
    if( SeekLoadFile(-4,SEEK_CUR) == FAILURE ) return FAILURE;
    if( GetBytes(data,4) == FAILURE ) return FAILURE;
    if( data[0] != 0x84 &&
     	( data[1] > 0x84 || data[1] <0x83 ) &&
     	( data[2] > 0x84 || data[2] < 0x82 ) &&
     	( data[3] > 0x84 || data[3] < 0x81 ) )
		return 1;
    return 2;
}  

#ifdef _DUMP_

/***************************************************************************
**
**	DisplayErrorRecord
**
***************************************************************************/
void LoaderServer::DisplayErrorRecord(U32 errorStartPos)
{
	U32 fCurPos = GetFileCurPos();
	if(SeekLoadFile(errorStartPos,SEEK_SET) == FAILURE ) return;
	int len = int(fCurPos - errorStartPos +3);
	U8* pdata = new U8[ len ];
	char* ptext = new char [ 2*len+4 ];
	if( pdata == NULL || ptext == NULL) {
		SeekLoadFile(fCurPos,SEEK_SET);
		return;
	}
	if( GetBytes(pdata,len) == FAILURE ) {
		SeekLoadFile(fCurPos,SEEK_SET);
		return;
	}
	SeekLoadFile(fCurPos,SEEK_SET);
	
	int j,k;
    for(int i = 0; i < len;i++) {
        j = (*(pdata+i) & 0x00FF ) >>4;
        k = (*(pdata+i)) & 0x000F;
        if( j < 10 ) ptext[2*i] =char( '0'+j );
        else ptext[2*i] = char('A'+j-10);
        if( k < 10 ) ptext[2*i+1] = char('0'+k);
        else ptext[2*i+1] = char('A'+k-10);
    }
    ptext[2*len] = '\0';
    strcat(ptext,"...");
    Message( "? Error Process Record at FilePos:%4lX",errorStartPos);
    Message(ptext);
    delete ptext;
    delete pdata;
}

#endif

/*****************************************************************************
**
**  MatchRecord
**
*****************************************************************************/
int LoaderServer::MatchRecord(U16 rtype) 
{
	/* Match 1 byte form the input file */
    if ( GetOneByte(&curByte) != GOOD ) return FAILURE;
    if (curByte != (U8) rtype)
        return FAILURE;
    return (GOOD);
}  /* MatchRecord */

/*****************************************************************************
**
**  Match2Record
**
*****************************************************************************/
int LoaderServer::Match2Record(U16 rtype,U16 rtype1)
{
    U8 byte[2];

	/* Match a 2-byte record from the input file */
    if ( GOOD != GetBytes(byte,2) ) return FAILURE;
    if ( (U8)rtype != byte[0] )
        return FAILURE;  /* will need resynch!! */
    if ( (U8)rtype1 != byte[1] )
        return FAILURE;
    return (GOOD);
}  /* Match2Record */

/******************************************************************************
**
**  SkipOver
**
**  Move the file pointer from blockPos for blocksize bytes.  If blockSize
**  is 0 then scan to the next BB signature.
**  Return error or GOOD
**
******************************************************************************/
int LoaderServer::SkipOver(U32 blockPos,U32 blockSize,U16 blockType,BOOL bGood) 
{
    U16 nextBlockType;
    U32 nextBlockPos = 0L;
    LONG filePos;
    BOOLEAN endBlock = FALSE;
    int nFlag ;     
    char *str;

#ifdef _DUMP_
	if( !bGood ) {
		DisplayErrorRecord(recordStartPos);
		Message("? Skip Over block Pos:%4lX Size:%4lX Type:%X",
			blockPos,blockSize,blockType);   
	}
#endif
    
	// If blockSize > 0 then seek to next block 
    //str = 0;
    if (blockSize) {
        nextBlockPos = blockPos + blockSize;
		// Throw away the current read buffer and set file pointer 
        if ( GOOD != SeekLoadFile(nextBlockPos,SEEK_SET) ) {
            return FAILURE;
        }            
    } 
    else {     
        nFlag = 1;
        while(nFlag) {
			// Blocksize is UNKNOWN - scan to the start of the next block
			// SyncTo() will stop at the IEEE_BE if first - set the endblock flag
			// then continue to scan
            //if (SyncTo(IEEE_BB, &filePos)!=GOOD) return FAILURE;
            if (SyncTo(IEEE_BB, &filePos,TRUE)!=GOOD) return FAILURE;
			// Saved the position to restore
            nextBlockPos = (U32) (m_uBufInFilePos+m_uBufPos);
			// Also check for going off the debug part -
			// Assume that ASW4 (debug) part is located before ASW5 (data)
			// endDebugPart = Hdr695.data_part and > 0
            if ( startAddr_ASW[5]&&nextBlockPos>=startAddr_ASW[5]) {
                nextBlockPos = startAddr_ASW[5];
                break;  /* out of while loop to stop */
            }
            int isCommand = Is695Command();
            if ( GOOD != GetOneByte(&curByte) ) return FAILURE;
            if ( curByte == IEEE_BB) {
                if ( GOOD != Get695BB(&blockSize,(LPSTR)str,&nextBlockType) )
                    return FAILURE;
            	if ( str ) delete str;
                if ( nextBlockType<1 || nextBlockType > 11) { 
                	continue;
                   //break; /* Not a valid block */
                } 
                switch(blockType) {
                case 10 : // BB_ASMBLOCK  :   
					// Nested block processing
                    if (nextBlockType != 11) nFlag = 0;
                    break;
                case 3 : // BB_MODULE :
                    if ( nextBlockType != 6 && nextBlockType != 4) nFlag = 0;
                    break;
                case 5 :
                    if ( nextBlockType != 5 ) nFlag = 0;
                    break;
                default :
                    if (endBlock);	// nFlag = 0;       //unreachable code
                    break;
                }
				// Nested block processing   
                if ( nFlag == 0 ) continue;
                //if (GOOD!=SkipOver(nextBlockPos, blockSize,nextBlockType)) 
                if (GOOD!=SkipOver(nextBlockPos, blockSize,nextBlockType,bGood)) 
                    return FAILURE;
            }
            else {   
            	U32 endA;
            	if ( isCommand == 1 ) {
            		//nextBlockPos++;
            		Get695Offset(&endA);
            		nextBlockPos = (U32) (m_uBufInFilePos+m_uBufPos);
            		break;
            	}
            	else {
            		if ( blockType==4 || blockType==6 || blockType==11 ) {
            			if( Get695Offset(&endA) == FAILURE ) continue;
            		}
            		if ( Is695Command() ) {
            			nextBlockPos = (U32) (m_uBufInFilePos+m_uBufPos);
            			break;
            		}
            		else continue;
            	}
				// reach the BE signature
				// Set endBlock flag & scan to beginning of the next block
/*
                if (!endBlock) 
                    endBlock = TRUE;            
                else {
					// NOTES: 02/24/94
					// When there are two consecutive BE then exit to 
					// end of the current block
                    nFlag = 0;
                }
*/
            }
        } 	// end of while 
      
		/* Restore to the block BB maker */
        if ( GOOD != SeekLoadFile(nextBlockPos, 0) ) return FAILURE;
    }

#ifdef _DUMP_
	recordStartPos = GetFileCurPos();
#endif

    return(GOOD);
}  /* SkipOver */

/******************************************************************************
**
**  SyncTo - Error recovery to the specified record.
**       rtype - record type to sync to
**       pfilePos - new file position after seek
**
******************************************************************************/
int LoaderServer::SyncTo(U16 rtype, long *pfilePos, BOOL bGood) 
{

#ifdef _DUMP_
	if( !bGood ) {
		DisplayErrorRecord(recordStartPos);
		Message("? Sync to Type:%x",rtype);
	}
#endif

   	// first, set filepos for error case 
    *pfilePos = -1L;
    while (1) {
        if ( GOOD != GetOneByte(&curByte) ) return FAILURE;
        if ( curByte == (U8)rtype) {
			// sync successful 
            if ( GOOD != UngetOneByte() ) return FAILURE;
            *pfilePos = (long) (m_uBufInFilePos+m_uBufPos);

#ifdef _DUMP_
			recordStartPos = GetFileCurPos();
#endif

            return(GOOD);
        }

		// We've reached the end of the block, new block detected.
		// This is an error case.  Since even local routines must return
		// RETCODE, we indicate error by return parameter.
        if ( (curByte == IEEE_BE) || (curByte == IEEE_BB) ) {
			// put it back so parsing can continue 
            if ( GOOD != UngetOneByte() ) return FAILURE;

#ifdef _DUMP_
			recordStartPos = GetFileCurPos();
#endif

            return(GOOD);
        }
    }
}  	// SyncTo 

/*****************************************************************************
**
**  Get695Number
**
*****************************************************************************/
/* Get695Number - handle IEEE number format (byte stream).
** Handles simple one-byte numerics, as well as the longer form,
** which sets the high bit on a byte-count field, followed by
** the bytes in the number.  Will get at most a 16-bit unsigned
**  quantity.  
*/
int LoaderServer::Get695Number(U16 *pn) 
{
    U8 nBytes;
    unsigned char data[2];

    *pn = 0;  /* in case byte count is zero */
    if ( GOOD != GetOneByte(&curByte) ) return FAILURE;
    if (curByte > 0x84) {
    	UngetOneByte();
    	return FAILURE;
    }
    else if (curByte > 0x80) {
        nBytes = (U8) (curByte & 0x7F);
//        if ( nBytes > 2 ) return FAILURE;
//        if ( curByte > 0x84 ) return FAILURE;
        if ( GOOD != GetBytes(data , nBytes) ) return FAILURE;
        if ( nBytes == 2 ) {
            *pn = BinToU16(data);
        }
        else if ( nBytes == 1 ) {
            *pn = (U16)data[0];  
        }
        else {
            *pn = 0;
        }
    }
    else if ( curByte == 0x80 )
    	*pn = 0; 
    else {
        *pn = (U16)curByte;
    }
    return (GOOD);
}  // Get695Number 

/******************************************************************************
**
**  Get695Offset
**
******************************************************************************/
int LoaderServer::Get695Offset(U32 *lAddr) 
{
	// lpoffset - pointer to long int, in which to store offset
    U8 nBytes;         
    U16 len;    
    U32 addr;
    unsigned char data[4];

    *lAddr = 0L;  // in case byte count is zero 
    if ( GOOD != GetOneByte(&curByte) ) return FAILURE;
    if ( curByte > 0x84 ) {
    	UngetOneByte();
    	return FAILURE;
    }
    else if ( curByte > 0x80 ) {
        nBytes = (U8)(curByte & 0x7F);
//        if ( nBytes > 4 ) return FAILURE;
//        if ( curByte > 0x84 ) return FAILURE;
        if ( GOOD != GetBytes(data , nBytes) ) return FAILURE;
        if ( nBytes == 4 ) {
            *lAddr = BinToU32(data);
        }
        else if ( nBytes == 3 ) {
            len = BinToU16(data);
            if ( m_absflag ) {
                addr = (U32) data[2];
                addr = addr << 16;
                addr += (U32) len;
            }
            else {
                addr = (U32)len;
                addr = addr << 8;
                addr += (U32) data[2];
            }
            *lAddr = addr;                
        }
        else if ( nBytes == 2 ) {
            len = BinToU16(data);
            *lAddr = (U32) len;
        }
        else if ( nBytes == 1 ) {
            *lAddr = (U32)data[0];  
        }
        else {
            *lAddr = 0;
        }
    } 
    else if ( curByte == 0x80 )
    	*lAddr = 0; 
    else {
        *lAddr = (U16)curByte;
    }
    return (GOOD);
}  /* Get695Offset */

/*****************************************************************************
**
**  Get695Idn - Get name field in IEEE 695 format
**
*****************************************************************************/
int LoaderServer::Get695Idn(char* &str) 
{
    U16 len;
    U8 c;
    unsigned char data[2];

    str = 0;
    if ( GOOD != GetOneByte(&curByte) ) return FAILURE;
    if ( curByte == 0xDE ) {
        if ( GOOD != GetOneByte(&c) ) return FAILURE;
        len = (U16)c;
    }
    else if ( curByte == 0xDF ) {
        if ( GOOD != GetBytes(data,2) ) return FAILURE;
        len = BinToU16(data);
    }
    else if ( curByte < 0x80 ) {
        len = (U16) curByte ;
    }
    else {
    	UngetOneByte();
    	return FAILURE;
    }

    str = new char [len+1];
    if ( str == 0 ) return FAILURE;
    if ( GOOD != GetBytes((U8 *)str , len) ) return FAILURE;
    str[len] = '\0';
    return GOOD;            
}  	// Get695Idn 

/******************************************************************************
**
**  Get695Nrecord - Get NameType record
**      pnindex - pointer to name index
**      name - name string
**
******************************************************************************/
int LoaderServer::Get695Nrecord(U32 *pIndex, LPSTR& name) 
{
   	//assumes no more than U16 names in file 
   	if ( Get695Offset(pIndex) != GOOD ) return FAILURE;
   	return Get695Idn( name );
}  	//Get695Nrecord 

/******************************************************************************
**
**  Get695Srecord
**
******************************************************************************/
int LoaderServer::Get695Srecord(U32 *pIndex, U32 *pValue) 
{
    U8 sbyte;                
    U8 oldByte;

    *pIndex = *pValue = 0L;  // initally, no value 
    if ( GOOD != GetOneByte(&curByte) ) return FAILURE;
    oldByte = curByte;
    switch ( curByte ) {
    case IEEE_SB :	// SB record = {$E5} {n1} 
        if ( GOOD != Get695Offset(pIndex) ) return FAILURE;
        curByte = oldByte;
        break;
    case IEEE_SA :	// SA record = {$E7}{n1}[n2][n3] 
        if ( GOOD != Get695Offset(pIndex) ) return FAILURE;
        if( Get695Offset(pValue) == GOOD )
        	Get695Offset(pIndex);
        curByte = oldByte;
        break;
    case IEEE_AS : //  AS record = {$E2}{ }{n1}{n2}  
        if ( GOOD != GetOneByte(&sbyte) ) return FAILURE;
/* 
   Note!!!  Should check validity of sbyte here.  Sometimes (like,
   at the end of the Data Part, additional records from another Part
   are read (Trail Part) and they don't fall in the range here.
   Once this processing is done, the check for INT_TOO_BIG in
   Get695Number can be enabled (use U32 and check - heed compiler
   warnings!
*/
        switch (sbyte) {
        case IEEE_ASS:   /* ASS record = {$E2}{$D3}{n1}{n2} */
        case IEEE_ASA:   /* ASA record = {$E2}{$C1}{n1}{n2} */
        case IEEE_ASB:   /* ASB record = {$E2}{$C2}{n1}{n2} */
        case IEEE_ASF:   /* ASF record = {$E2}{$C6}{n1}{n2} */
        case IEEE_ASM:   /* ASM record = {$E2}{$CD}{n1}{n2} */
        case IEEE_ASL:   /* ASL record = {$E2}{$CC}{n1}{n2} */
        case IEEE_ASP:   /* ASP record = {$E2}{$D0}{n1}{n2} */
        case IEEE_ASR:   /* ASR record = {$E2}{$D2}{n1}{n2} */
        	if ( GOOD != Get695Offset(pIndex) ) return FAILURE;
        	if ( GOOD != Get695Offset(pValue) ) return FAILURE;
            curByte = sbyte;
            break;
        default :
    		*pIndex = -1;
    		UngetOneByte();
    		UngetOneByte();
            return FAILURE;    
        }             
        break;
    default :
    	*pIndex = -1;
    	UngetOneByte();
        return FAILURE;    
    }
    return (GOOD);
}  	// Get695Srecord 

/*****************************************************************************
**
** ProcessATN - Process ATN record
**
*****************************************************************************/
int LoaderServer::ProcessATN(U32 *pIndex, U32 *pType, U16 *n3) 
{
   	if ( Get695Offset(pIndex) != GOOD ) return FAILURE;
   	if ( Get695Offset(pType) != GOOD ) return FAILURE;
	// ATN type return 
	if ( Get695Number(n3) != GOOD) return FAILURE; 
   	return(GOOD);
}  	// ProcessATN 

/******************************************************************************
**
**  Get695Time
**
******************************************************************************/
int LoaderServer::Get695Time(TIMESTAMP_TYPE *pts) 
{
   	if( Get695Number((U16 *) &(pts->year))==FAILURE ) return FAILURE;
   	if( Get695Number((U16 *) &(pts->month))==FAILURE ) return GOOD;
   	if( Get695Number((U16 *) &(pts->day))==FAILURE ) return GOOD;
   	if( Get695Number((U16 *) &(pts->hour))==FAILURE ) return GOOD;
   	if( Get695Number((U16 *) &(pts->minute))==FAILURE ) return GOOD;
   	Get695Number((U16 *) &(pts->second));
   	return(GOOD);
}  	// Get695Time 
/****************************************************************************
**
**	Get695Letter
**
****************************************************************************/
int LoaderServer::Get695Letter(U8 *ch) 
{
    if ( GOOD != GetOneByte(ch) ) return FAILURE;
    if ( *ch < 0xc1 || *ch > 0xda  ) {
    	UngetOneByte();
    	return FAILURE;
    }
    return GOOD;
}

/*****************************************************************************
**
**  ProcessASN - Used for both ASN and ATN Global type record
**
*****************************************************************************/
int LoaderServer::ProcessASN(U32 *pType, U32 *pValue) 
{
   if ( Get695Offset(pType) != GOOD) return FAILURE;
   if ( Get695Offset(pValue) != GOOD) return FAILURE;
   return(GOOD);
}  /* ProcessASN */
                
/******************************************************************************
**
**  ProcessATI
**       pIndex   - pointer to name index
**       pType    - pointer to type index
**       pAttr    - pointer to attribute definition
**       pNumber  - pointer to number of elements (if *pType != 0)
**
******************************************************************************/
int LoaderServer::ProcessATI(U32 *pIndex, U32 *pType, U16 *pAttr,U16 *pNumber) 
{
	// ATI :
	// {$F1}{$C9}{symbolname index}{symboltype index}{attribute}{num elements}
    *pNumber = 0;
	// symbolname index {n1}
    if ( GOOD != Get695Offset(pIndex) ) return FAILURE;
	// symtype index    {n2}
    if ( GOOD != Get695Offset(pType) ) return FAILURE;
	// attribute        {n3}
    if ( GOOD != Get695Number(pAttr) ) return FAILURE;

    if (*pType != 0L) {
		// num elements  {n4}
        if ( GOOD != Get695Number(pNumber) ) return FAILURE;
    }
    else Get695Number(pNumber);
    return(GOOD);
}  	/* ProcessATI */

/******************************************************************************
**
**  StripName
**
** Strip leading underscore from public symbols (code and data symbols).
** In this way, publics which were extern records during symbol loading
** of the Debug Part of the file will correctly be found and updated
** with address information from the Public Part.  Also, symbols linked
** in from library code/non-C objects will look proper to the user, who
** does not expect to find an underscore prepended (unless their mind
** has been warped by excessive exposure to Unix environments..)
** Return pointer to stripped-string.
**
******************************************************************************/
LPSTR LoaderServer::StripName(LPSTR lpn1) 
{
/* lpn1 - pointer to original string */
    if (lpn1[0] == '_')
        return ((LPSTR)&lpn1[1]);
    return (lpn1);
}  /* StripName */

/*****************************************************************************
**
** Get695BB - Return Block Begin (BB) signature
**
** pblockSize   - pointer to block size in bytes
** lpblockName  - block name (module, function name, etc.)
** blockType    - block type on sucess BB1, BB2, BB3, BB4,...
**
*****************************************************************************/
int LoaderServer::Get695BB(U32 *pblockSize,LPSTR& lpblockName,U16 *blockType) 
{
	// All the BB (block begin) record types indicate overall program
	// structure, and symbol definitions for such entities (module, function,
	// line number).  All BB records have at least the fields returned
	// by this routine.  Some may require additional information.
//    if ( GOOD != GetOneByte(blockType) ) return FAILURE;
    if ( GOOD != GetOneByte(&curByte) ) return FAILURE;
    *blockType = (U16) curByte;
    if ( Get695Offset(pblockSize)!=GOOD ) return FAILURE;
    if ( Get695Idn(lpblockName)!=GOOD ) return FAILURE;
    return(GOOD);
}  /* Get695BB */

/*****************************************************************************
**
**  ProcessTY - Define Type record
**
** ptindex - pointer to type index
** pnindex - pointer to name index
** pstype - pointer to symbol type
**
*****************************************************************************/
int LoaderServer::ProcessTY(U32 *ptindex,U32 typeOffset, U32 *pnindex, U16 *pstype) 
{
    if ( Get695Offset(ptindex) != GOOD ) return FAILURE;
    if ( *ptindex >= 0x100 ) *ptindex += typeOffset;
    if ( MatchRecord(IEEE_TY2) != GOOD ) return FAILURE;
    if ( Get695Offset(pnindex) != GOOD ) return FAILURE;
    if ( Get695Number(pstype) != GOOD ) return FAILURE;
    return GOOD;
}  /* ProcessTY */

/*****************************************************************************
**
**  ProcessATN16 - Process record: ATN 16 (Constant definition)
**
*****************************************************************************/
int LoaderServer::ProcessATN16(U32 *nValue, LPSTR& defName) 
{
    BOOLEAN done = FALSE, matchX2 = FALSE;
    U32 nIndex;
    U32 pcLoc;
    long filePos;
   
	// ATN16 - {ATN header}{x1}[x2][x3]|[x4]|ASN
	// where: [x3] is a numeric, [x4] is a string value
	// Also, there might be an ASN record indicating the PC where
	// the definition occurs

	// get {x1} - Symbol class 
    if ( GOOD != GetOneByte(&curByte) ) return FAILURE; 
    while ( !done ) {
        if ( GOOD != PeekByte(&curByte) ) return FAILURE; 
        switch( curByte ) {
        case IEEE_NN :
        case IEEE_BB :   
        case IEEE_BE :   
            return(GOOD);
        case 0 :
        case 1 :
            /* get the optional [x2] */
            if (!matchX2) {
                if ( GOOD != GetOneByte(&curByte) ) return FAILURE; 
                matchX2 = TRUE;
            } else
                SyncTo( IEEE_NN, &filePos );
            break;
        default :
            /* Get the optional [x3] | [x4] */
            if ( curByte < 0x80 || curByte >= 0x84 ) {
                SyncTo(IEEE_NN, &filePos );
            }
            else if ( Get695Offset(nValue) != GOOD ) {
                SyncTo(IEEE_NN, &filePos );
            }
            if ( GOOD != PeekByte(&curByte) ) return FAILURE; 
            switch( curByte ) {
            case IEEE_NN:
            case IEEE_BB:
            case IEEE_BE:
                return(GOOD);
            case IEEE_AS :   // 0xE2
				// There might be an ASN record at the end of ATN16
                if ( Match2Record(IEEE_AS , IEEE_ASN) == GOOD ) 
                    return( ProcessASN(&nIndex, &pcLoc) );
                else {
                    if ( SyncTo(IEEE_NN, &filePos) != GOOD )
                        return FAILURE;
                }
                break;                  
            default:
				// NOTES: 09/20/93 - Nghia
				// Usually [x3] is zero, then there must be an [x4] string
				// else there will be no string present - MRI 4.3d
                if ( *nValue||Get695Idn(defName)!=GOOD ) { 
                    SyncTo(IEEE_NN, &filePos);
                }
                break;
            } // end of switch 
        } // end of switch 
    } 
    return GOOD;	// unreachable code
}  	// ProcessATN16 

/*****************************************************************************
**
** PBBFunction - Global or Static function of BB4 and BB6
**
** pnstack - pointer to number of bytes for stack
** prtn_type - pointer to type index for function return value
** typeOffset - fix-up value for return type
** poffset - pointer to offset for code block
**
*****************************************************************************/
int LoaderServer::PBBFunction(U32 *pnstack, U32 *prtn_type, U32 typeOffset,
                    U32 *poffset) 
{
   if ( GOOD != Get695Offset(pnstack) ) return FAILURE;
   if ( GOOD != Get695Offset(prtn_type) ) return FAILURE;
   if ( *prtn_type >= 0x100 ) *prtn_type += typeOffset;
   if ( GOOD != Get695Offset(poffset) ) return FAILURE;
   return(GOOD);
}  /* PBBFunction */

/*****************************************************************************
**
**  ProcessATN7 - Process record: ATN 7 (line number)
**
*****************************************************************************/
int LoaderServer::ProcessATN7(U16 *pline, U16 *pcol) 
{
	//  pline - pointer to line number, pcol - pointer to column number 
	//  ATN7 - x1 x2 [x3] [x4]
    if ( GOOD != Get695Number(pline) ) return FAILURE;
    if ( GOOD != Get695Number(pcol) ) return FAILURE;
	// NOTES: Nghia - Check for 2 extra fields of ATN [x3] and [x4] 
	U16 dummy;
    if ( Get695Number(&dummy) == GOOD )
        Get695Number(&dummy);
    return GOOD;
}  	// ProcessATN7 

/*****************************************************************************
**
**  ProcessATNMisc - (Procedure | variable | module miscellaneous)
**            ptypeid - pointer to misc record
**            pnrecs - pointer to number of records which follow
**
*****************************************************************************/
int LoaderServer::ProcessATNMisc(U16 /*Misc*/,U32 *ptypeid, U32 typeOffset, U16 *pnrecs) 
{
    U32 miscType;  //miscellaneous record type
    char *str;
   
	// This is really the misc record type - see Appx B 
    if ( GOOD != Get695Offset(ptypeid) ) return FAILURE;
    miscType = *ptypeid;
    if ( *ptypeid >= 0x100 ) *ptypeid += typeOffset;
/* 
		The following pmisc types are understood:
    	PMISC_1:     procedure return address (HP tools/Ford code)
    	PMISC_51:    language translator comment string
    	PMISC_57:    jump table description
    	PMISC_77:    undocumented (optimized MRI output)
    	PMISC_80:    C++ information

		NOTES: Each pmisc type has a unique format.  Since we want to
		be open-ended and handle random loadfiles built with random tools,
		we assume that unrecognized types have the same general format
		(usually a safe assumption), and issue a warning (and take an
		action item to contact the toolchain provider).  For unknown pmisc
		types, we still return the number of records, the caller will eat
		that many ASNs.
*/
    if ( GOOD != Get695Number(pnrecs) ) return FAILURE;
    if ( miscType == 55 ) {			// module misc for 68k
    	Get695Idn(str);
    	if ( str ) delete str;
    }
    //if ( miscType != 77 ) {
        if ( PeekByte(&curByte) != GOOD ) return FAILURE;
        if ( curByte != IEEE_AS && curByte != IEEE_AT )
			// Don't ask why but all other pmisc have it - Throw away 
			// NOTES: 04/21/94 - Nghia
			// MRI generated an extra 1 byte (BUG) after nitems with their DOS
			// compiler, However this byte does not exist in UNIX version.
			// The Loader has to detect and handles it.
			// unused - MRI DOS compiler BUG 
            if ( GetOneByte(&curByte) != GOOD ) return FAILURE;
    //}  
/*
    switch (pmiscType) {
    case 1 :
    case 51 :
    case 57 :
    case 77 :
    case 80 :
        break;
    default:
        break;
    }
*/
    // Process all ASN and ATN records
    char *blockName;
    U32 nindex,tindex,nvalue;
    U16 atype; 
    for (U16 i = 0; i < *pnrecs ; i++) {
        if ( GOOD != PeekByte(&curByte) ) return FAILURE;
        if ( curByte == IEEE_AS ) {
            Match2Record(IEEE_AS , IEEE_ASN);
            ProcessASN(&nindex, &nvalue);
        } 
        else if (curByte == IEEE_AT ) {
            Match2Record(IEEE_AT, IEEE_ATN);
            ProcessATN(&nindex, &tindex, &atype);
            if ( tindex > 0x100 ) tindex += typeOffset;
            if ( atype != 65 ) return FAILURE;
            Get695Idn( (LPSTR)blockName );
            if ( blockName ) delete blockName;
        } 
        else   return FAILURE;
    } 
    return GOOD;
}  	// ProcessATNMisc

/*****************************************************************************
**
**  ProcessATN62 - (Procedure miscellaneous)
**    ATNs that are local to a procedure handled here.
**
*****************************************************************************/
int LoaderServer::ProcessATN62(U32 *ptypeid, U32 typeOffset, U16 *pnrecs) 
{
/* ptypeid - pointer to misc record
  pnrecs - pointer to number of records which follow
*/
    U32 pmiscType;  /* procedure miscellaneous record type */
   
/* This is really the misc record type - see Appx B */
    if ( GOOD != Get695Offset(ptypeid) ) return FAILURE;
    if ( *ptypeid >= 0x100 ) *ptypeid += typeOffset;
    pmiscType = *ptypeid;
/* The following pmisc types are understood:
**    PMISC_1:     procedure return address (HP tools/Ford code)
**    PMISC_51:    language translator comment string
**    PMISC_57:    jump table description
**    PMISC_77:    undocumented (optimized MRI output)
**    PMISC_80:    C++ information
**
** NOTES: Each pmisc type has a unique format.  Since we want to
** be open-ended and handle random loadfiles built with random tools,
** we assume that unrecognized types have the same general format
** (usually a safe assumption), and issue a warning (and take an
** action item to contact the toolchain provider).  For unknown pmisc
** types, we still return the number of records, the caller will eat
** that many ASNs.
*/
    if ( GOOD != Get695Number(pnrecs) ) return FAILURE;
    if ( pmiscType != 77 ) {
        if ( GetOneByte(&curByte) != GOOD ) return FAILURE;
        if ( UngetOneByte() != GOOD ) return FAILURE;
        if ( curByte != IEEE_AS && curByte != IEEE_AT )
/* Don't ask why but all other pmisc have it - Throw away */
            if ( GetOneByte(&curByte) != GOOD ) return FAILURE;
    }  
/*
    switch (pmiscType) {
    case 1 :
    case 51 :
    case 57 :
    case 77 :
    case 80 :
        break;
    default:
        break;
    }
*/
    return GOOD;
}  /* ProcessATN62 */

/*****************************************************************************
**
**  getBlockEndAddress - Get the end address of a block 
**
*****************************************************************************/
int LoaderServer::getBlockEndAddress(U32 endBlockPos,
                    U32 fStartOffset, U32 *fEndOffset) 
{
   int i, j;
   U8 endAddrBuf[8];
   
   /* We have to find the end-address for the function.  This
   ** is the only place in the file where this information is
   ** kept.  It is a bit tricky in the cases to consider, in
   ** the current algorithm to backtrack looking for the address.
   ** Note that it is still quicker to backtrack than to process
   ** all the locals (we are an ondemand loader, remember?).  The
   ** previous algorithm used here (PV 1.4 and previous) failed on
   ** at least one customer loadfile (it backtracked by FN_ENDADDR_OFFSET
   ** bytes and looked forward), by getting confused by a local
   ** address frame offset of 'FF FF FF F9'.
   **
   ** (where F9 is the end-marker for function block (RT_BE),
   ** and F8 is the start of the next function block)
   ** Here are some templates of what is handled:
   **
   **    F9 82 E4 35    normal case
   **    F9 82 B4 F9 F8   note that F9 can be part of the end-address,
   **                   the algorithm needs to verify that what follows
   **                   F9 is a valid address (in this case, there are
   **                   no bytes that follow).
   **    F9 37 F8       single-byte number format accepted, as well
   **                   as the multi-byte offset format given above
   **    F9 84 A2 B4 F9 B6 F8
   **                   Here F9 marker is found within a multi-byte
   **                   offset address, we check carefully that the
   **                   byte that follows the F9 marker is either a
   **                   straight number prefix ($80) indicating a multi-
   **                   byte offset number, *or* a single-byte number
   **                   which follows.  This F9 kicks out since the
   **                   B6 that follows is neither.  So we keep backing
   **                   up till the next F9.
   **    F9 84 A2 36 F9 32 F8
   **                   Though there appears to be a single-byte address
   **                   following the first (from reverse search) F9,
   **                   a check is done to ensure the function
   **                   end-address is larger than the start address
   **                   (both are known at initial load time).  If the
   **                   end address is smaller, the search continues.
   */
   /* local buffer only includes end bytes from previous block */
    SeekLoadFile(endBlockPos-7,0);

   	/* get buffer for local processing */
    GetBytes(endAddrBuf,8);
	/* Scan backward in local buffer, looking for BE marker
	** indicating end-function block address.
	*/
    for (i = 6, j = 0; i >= 0; --i,++j) {
		/* be sure we have atleast one byte to process */
        if (endAddrBuf[i] == IEEE_BE && j != 0) {
            if ( IsValid695Offset(&endAddrBuf[i+1],(U16)j, 
                fEndOffset)== GOOD ) {
				/* be sure end address > start address of function */
                if (*fEndOffset > fStartOffset)
                    break; /* !!! else continue searching */
            }
        }
   }          
   if ( i < 0 ) return FAILURE;
   return GOOD;
} /* getBlockEndAddress */

/*****************************************************************************
**
**  IsValid695Offset - determine if buffer is a valid address
**
*****************************************************************************/
int LoaderServer::IsValid695Offset(U8* pBuffer, U16 len, U32 *pAddr) 
{
    U8 pbyte;
    U16 nbytes;
    U32 nvalue = 0L;
    int i;

    pbyte = pBuffer[0];
    if ( pbyte > 0x80 && pbyte <= 0x84 ) {
        nbytes = (U8) (pbyte - 0x80);
		/* be sure we have this many bytes in buffer */
        if (nbytes > len-1)
            return FAILURE;
        for (i=1; (U16)i<nbytes+1; i++) {
            nvalue = nvalue << 8;
            nvalue |= pBuffer[i];
        }
        *pAddr = nvalue;
    } else {
	/* must match single-byte number format */
        if (pbyte <= 0x80) {
            *pAddr = (U32)pbyte;
        } else {  /* invalid address */
            return FAILURE;
        }
    }

    return GOOD;
}  /* IsValid695Offset */

/******************************************************************************
**
**  Get695STrecord
**
******************************************************************************/
int LoaderServer::Get695STrecord(U16 *pattr, U16 *stType) 
{
    U8 sprefix;

    *pattr = 0;  /* initially, no attribute */
    if ( GOOD != GetOneByte(&sprefix) ) return FAILURE;
    switch (sprefix) {
    case 0xC1:		// A
        if ( MatchRecord(0xD3)!=GOOD ) return FAILURE;
        if ( Get695Letter( &curByte ) == GOOD ) *pattr = (U16) curByte;
/*
        if ( PeekByte(&curByte) != GOOD ) return FAILURE;
        if ( curByte == 0xD0 || curByte == 0xD2 || curByte == 0xC4 ) {
            GetOneByte(&curByte);
            *pattr = (U16) curByte ;                                  
        }    
*/
        *stType = 1;
        break;
	// 09/12/94 - Nghia
	// Allow fall thru to handle C2 type for SDS toolchain         
    case 0xC2:      // B
    case 0xD4:		// T
        *stType = 1;
        break;
    case 0xC3:      // C
        if ( GOOD != GetOneByte(&curByte) ) return FAILURE;
        *pattr = (U16) curByte ;                                  
        *stType = 2;
        break;
    case 0xC5:      // E
        if ( GetOneByte(&curByte) != GOOD ) return FAILURE;
        if ( curByte == 0xDA )
            *stType = 4;
        else if ( curByte == 0xC1 ) {
            if ( GetOneByte(&curByte) != GOOD ) return FAILURE;
            *pattr = (U16) curByte;
            *stType = 3;
        }
        break;
    case 0xDA:       // Z
        if ( GetOneByte(&curByte) != GOOD ) return FAILURE;
        if ( curByte == 0xCD )
            *stType = 6;
        else if ( curByte == 0xC3) {
            if ( GetOneByte(&curByte) != GOOD ) return FAILURE;
            *pattr = (U16) curByte;
            *stType = 5;
        }
        break;
    default:
        return FAILURE;
    }
    return(GOOD);
}  	/* Get695STrecord */

/******************************** E O F ***********************************/
