// ldrsvr.cpp : implementation file
//

#include "stdafx.h"
#include <stdarg.h>
#include <ctype.h>
#include <sys\types.h>
#include <sys\stat.h>
#include "io.h"

#include "abiextfn.h"
#include "ldrsvr.h" 
#include "bankinit.h"
#include "srcexp.h"
#include "hosterrs.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif           

extern DWORD g_dwLoadInitPC;
     
/////////////////////////////////////////////////////////////////////////////
// CLdrSvr


 CLdrSvr::CLdrSvr()
 { 
   LoadInit(); 
 }
 
 CLdrSvr::~CLdrSvr()
 {
  ClearUpModuleBlock();
  if(m_lpBuffer) delete (m_lpBuffer);
  m_lpBuffer = NULL;
 }

 int CLdrSvr::TestKey(WORD wKey)
 {   
    MSG msg;
    if(PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
        PM_NOREMOVE|PM_NOYIELD)) {
        PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
            PM_REMOVE|PM_NOYIELD);
        if(msg.message == WM_KEYDOWN && msg.wParam == wKey) 
            return  1;        
    }            
    return  0;
 }
 
 void CLdrSvr::TestMessage(void)
 {
    MSG message;
    while (::PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
        ::TranslateMessage(&message);
        ::DispatchMessage(&message);
    }
 }

 void CLdrSvr::LoadInit()
  {
  // Initializing variables that may be used by loader 
    m_dwErrMsg =      0;
    m_hLdrFile =      0;
    m_lStartAddress = 0X2080;
    m_time.year =     -1;
    m_time.hour =     -1;
   
    m_bSymLoaded  =  FALSE; 
    m_IsLoaded    =  FALSE;
    m_bSwitchOn   =  FALSE;
    m_nLoadToBank =  0;
    m_bAppSym     =  0;
    
    m_nCompilerType = LDR_UNKNOWN;
    m_nLdrOptFlag =   LDR_DEFAULT; 
    m_where =         LOAD_FROM_DIALOG; 

    m_pCurBlock = NULL;
    m_lpBuffer = new U8[LDR_BUFSIZE];
    if ( m_lpBuffer == 0 ) 
     {
        AfxMessageBox("Out Of Memory!");
        return ;
     }
    m_uBufInFilePos = 0;
    m_uBufSize =      0;
    m_uBufPos =       0;
    m_typeDelta =     0;
    m_typeNum =       0;
    m_symbolNo =      0; 
    m_typeNo =        0;
    m_moduleNo =      0;
    m_uCurTypeDelta = 0;
  }   

// get path handle of file         
BOOL CLdrSvr::GetFileInfo()
 {
   char path_buffer[_MAX_PATH];
   char drive[_MAX_DRIVE];
   char dir[_MAX_DIR];
   char fname[_MAX_FNAME];
   char ext[_MAX_EXT];  
   
   if ((m_hLdrFile=_lopen(m_strFile,READ | OF_SHARE_DENY_WRITE))
         == HFILE_ERROR){  
        return 0;
   }
   m_lFileLen = _filelength(m_hLdrFile);
          
   _splitpath(m_strFile, drive, dir, fname, ext );
   _makepath(path_buffer,drive,dir,NULL,NULL);
   m_strFilePath = path_buffer;
   lstrcat(fname,ext);
   m_strFileName = fname;
   return 1; 
  }  

BOOL CLdrSvr::ClearUpModuleBlock(void)
{             
    if (m_modNode.name ) {
        delete( m_modNode.name );
        m_modNode.name = 0;
    }
    if ( m_modNode.lpblock ) {
        if ( ClearUpBlockBlock(m_modNode.lpblock) == 0 )
            return 0;                           
        delete( m_modNode.lpblock );   
        m_modNode.lpblock = 0;
    }
    
    return 1;
}

BOOL CLdrSvr::ClearUpBlockBlock(struct BlockBlock far *node)
{                                                        
    if ( node->funcName ) {
        delete( node->funcName);
        node->funcName = 0;
    }
    if ( node->son ) {
        if ( ClearUpBlockBlock(node->son) == 0 )
            return(0);        
        delete( node->son );   
        node->son = 0;
    }
    if ( node->next ) {
        if ( ClearUpBlockBlock(node->next) == 0 )
            return(0);  
        delete( node->next );  
        node->next = 0;
    }
    return(1);
}
    
BOOL CLdrSvr::ModuleNodeInit(void)
{
    m_modNode.codeaddr.segType = (SEGMENTTYPE) SEG_CODE;
    m_modNode.codeaddr.startAddr = DEFAULT_START_ADDR;
    m_modNode.codeaddr.endAddr = DEFAULT_END_ADDR;
    m_modNode.time.year = -1;
    m_modNode.time.hour = -1;
    m_modNode.offset = 0;
    m_modNode.symno = 0;
    m_modNode.blkcnt = 0;
    m_modNode.linecnt = 0;
    m_modNode.scope = 0;
    return 1;
}   
                  
BOOL CLdrSvr::GetName(U8 *& str)
{                                   
    
    GetOneByte(&m_uCurByte);
    if(m_uCurByte == 0){
       str = NULL;
       return 1;
    }
    
    if(m_nCompilerType == LDR_OMF96){
	    if(int(m_uCurByte) > 40){
	       m_dwErrMsg = ER_LDR_LONG_NAME;
	       return 0;
	    }
	}
    str = new U8[m_uCurByte+1];
    if ( str == 0 ) {
        return 0;
    }
    if ( !GetBytes(str , m_uCurByte) ) {
        delete str;
        return 0;
    }
    str[m_uCurByte] = '\0';
    return 1;
}

BOOL CLdrSvr::SeekLoadFile(long off , int nOrg)
{                                               
    if ( nOrg == 1 ) {
        long i;
        i = off + (long)m_uBufPos;
        if ( (i>=0L) && (i<(long)m_uBufSize) ) {
            m_uBufPos = (U16) i;
            return 1;
        }
        nOrg = 0;
        off = (long) (m_uBufInFilePos+m_uBufPos) + off;
    }
    if ((m_uBufInFilePos=_llseek(m_hLdrFile,off,nOrg))==HFILE_ERROR){
        return ( 0 );                                                
    }
    m_uBufSize = (U16) _lread(m_hLdrFile , m_lpBuffer , LDR_BUFSIZE);
    if ( m_uBufSize == 0 ) return( 0 );
    m_uBufPos = 0;
    return( 1 );
}            


//skip record of fixed length   
BOOL CLdrSvr::SkipRecord(U32 len)
{ 
  U8 * data;
  
  data = 0;
  
  if(len < LDR_BUFSIZE ){
     data = new U8[len];
     if(data == 0){
        m_dwErrMsg = ER_LDR_MEMORY_ALLOC;
        return 0;
     }
     if(!GetBytes(data , len)){
         m_dwErrMsg = ER_LDR_READ_FILE;	
         return 0;                        
     }                            
  }
  else if(!SeekLoadFile((U32)len,1)){
           m_dwErrMsg = ER_LDR_READ_FILE;	
           return 0;
   }  
  if(data) delete data;
  return 1;
}

BOOL CLdrSvr::LoadFile()
 {
   int err;

#ifdef _LINK_ABI  	
   
   
   unsigned long uch;
   
   if(emuGetCpuStatus(&uch)!=ICE_OK){
      m_dwErrMsg = ER_LDR_GET_CPU;
      return 0;
   }
   if ( uch&0x0010 ) {
    	m_dwErrMsg = ER_LDR_HALT_CPU;
    	return 0;
	 }
#endif

// add by Richard to get initial pc address before loading file
      ADDR addr;

      addr.addrType = 0;
      addr.addr = 0xffff;

      if(emuReset(addr) ==ICE_OK){
	      if (ICE_OK != ::emuGetReg(0, 0, &g_dwLoadInitPC)){
    	  		g_dwLoadInitPC = -1;
    	  }
      }
                                                               
                                                               
   if(!GetFileInfo()){
       return 0;
   }
    
   err = LoadProcess() ;

   //close file
   if(_lclose(m_hLdrFile)==HFILE_ERROR){
      return 0;
   }
   
   if(err == 0){
      Error(m_dwErrMsg,0);
      return 0;
   }  
   m_IsLoaded = TRUE;
   if(LOAD_SYM( m_nLdrOptFlag)){ 
      if(m_nCompilerType!=LDR_HEX196)
         m_bSymLoaded = TRUE;
      else                   
         m_bSymLoaded = FALSE;
#ifndef _LONG_ 
       SymAddLoadEnd();
#endif
   }                 
#ifndef _LONG_     
   if((m_where == LOAD_FROM_DIALOG)&&(m_nLdrOptFlag & LDR_STATUS)){
       TestMessage();
   }                       
                            
#ifdef _LINK_ABI  	
   if(LOAD_CODE(m_nLdrOptFlag)){
      addr.addrType = 0;
      addr.addr = 0xffff;

      if(emuReset(addr)!=ICE_OK){
         Error("Can not reset HardWare");
         return 0;
      }
      
      if(emuSetReg( 0, 4 , 0x18 ) != ICE_OK ) {
         Error("Can not set SP address");
         return 0;
       }
    }                     
#endif    
#endif
   return 1;
 }
  
 BOOL CLdrSvr::LoadCmd(int argc , char * argv[]) 
  {
    int nErr;
    
    m_where = LOAD_FROM_SHELL;
    
    nErr = LdrProcessArgs(argc , argv );
    if(!nErr){
       Error("Unknowed Arguments");
       return 0;
     }
   m_bSpecSymbol = LOAD_SYSTEM(m_nLdrOptFlag)?1:0;
    
#ifndef _LONG_ 
    if(!m_bAppSym) SymRemoveSymbols();
    else{
    //for multiple loaded
       RETCODE retCode;
       
       m_typeDelta = 0;
       retCode = SymGetTypeIndexMax(&m_typeDelta);
       if(retCode != GOOD){
          m_dwErrMsg = ER_LDR_SYM_SERVER;
          return 0;
       }
    }
#endif
	BOOL bLoadOK = LoadFile(); 
	
	//call source dll
    SrcLoadCmd(bLoadOK, m_strFile);
    if(!bLoadOK){
       Error("Cann't download file");
       return 0;
     }
   
    m_where = LOAD_FROM_DIALOG;
    return 1;
  }
 
 BOOL CLdrSvr::LdrProcessArgs(int argc , char * argv[]) 
  {
   int i;     
   char temp[ARGLEN];
   int nFlags;
   
   nFlags = LDR_DEFAULT;       /* load code, symbols, display progress ,
                                    issue warnings  */
/* process options */
    for (i = 2; i < argc; i++) {
        lstrcpy((LPSTR)temp, (LPSTR)argv[i]);
        switch (toupper(temp[0])) {
         case 'A':
            if (strnicmp(temp, "APPEND", 6) == 0) m_bAppSym = 1;
            else return 0;
            break;            
         case 'C':   /* load code */
            if (strnicmp(temp, "COD", 3) == 0) nFlags |= LDR_CODE;
            else return(0);
            break;
         case 'N':   /* turn off option */
            if (strnicmp(temp, "NOSYM", 5) == 0)
                nFlags &= ~LDR_SYMBOL;
            else if (strnicmp(temp, "NOCOD", 5) == 0)
                nFlags &= ~LDR_CODE;
            else if (strnicmp(temp, "NOPRO", 5) == 0)
                nFlags &= ~LDR_STATUS;
            /* no more warning */
            else if (strnicmp(temp, "NOWAR", 5) == 0) 
                nFlags &= ~LDR_WARNING;
            else if (strnicmp(temp, "NOSYSTEM", 8) == 0)
                nFlags &= ~LDR_SYSTEM;
            else return 0;
            break;
         case 'P':   /* progress indicator */
            if (strnicmp(temp, "PRO", 3) == 0)
                nFlags |= LDR_STATUS;
            else if (strnicmp(temp, "P0:", 3) == 0)
                m_nLoadToBank = 1;
            else if (strnicmp(temp, "P1:", 3) == 0)
                m_nLoadToBank = 2;
            else if (strnicmp(temp, "P2:", 3) == 0)
                m_nLoadToBank = 3;
            else if (strnicmp(temp, "P3:", 3) == 0)
                m_nLoadToBank = 4;
            else return 0;
            break;
         case 'S':   /* symbol load */
            if (strnicmp(temp, "SYM", 3) == 0)
                nFlags |= LDR_SYMBOL;
            else if (strnicmp(temp, "SYSTEM", 6) == 0){
                nFlags |= LDR_SYSTEM;                  
                m_bSpecSymbol = TRUE;
            }
            else return 0;
            break;
         case 'W':   /* warnings */
            if (strnicmp(temp, "WAR", 3) == 0) 
                nFlags |= LDR_WARNING;
            else return 0;
            break;
         case 'X':   /* warnings */
            if (strnicmp(temp, "X0:", 3) == 0) {
                nFlags |= LDR_TODATA;
                m_nLoadToBank = 1;
            }
            else if (strnicmp(temp, "X1:", 3) == 0) {
                nFlags |= LDR_TODATA;
                m_nLoadToBank = 2;
            }
            else return 0;
            break;
         default:
            return 0;
        } 
    }     
    m_nLdrOptFlag = nFlags;
    return 1;
 }  /* LdrProcessArgs */

long CLdrSvr::GetFileCurPos()
 { 
  return (long)(m_uBufInFilePos+m_uBufPos) ; 
 }

BOOL CLdrSvr::IsOMF96() 
 { 
  if (m_nCompilerType == LDR_OMF96) 
      return TRUE;
  else 
      return FALSE; 
 }
  
/***************************************************************************
*                                                                          *
*  BinToU16 - convert 2 byte to U16 value                                  *
*  parameter :                                                             *
*       s  --  byte pointer ( input )                                      *
*  return value :                                                          *
*       U16 value                                                          *
*                                                                          *
***************************************************************************/
U16 CLdrSvr::BinToU16(U8 *s)
{
    U16 ui ;
       
    if ( m_bHiLoFlag ) {
        ui = (U16) s[1] ;
        ui = (ui<<8) + (U8)s[0];
    }
    else {   
        ui = (U16) s[0];
        ui = (ui<<8) + (U8)s[1];
    }
    return (ui);
}
/***************************************************************************
*  BinToU32 - convert 4 byte to U32 value                                  *
*  parameter :                                                             *
*       s  --  byte pointer ( input )                                      *
*  return value :                                                          *
*       U32 value                                                          *
***************************************************************************/
U32 CLdrSvr::BinToU32(U8 *s)
{
    U32 ul;

    if ( m_bHiLoFlag ) {
        ul = (U32) s[3];
        ul = (ul<<8) + (U8) s[2];
        ul = (ul<<8) + (U8) s[1];
        ul = (ul<<8) + (U8) s[0];
    }
    else {
        ul = (U32) s[0];
        ul = (ul<<8) + (U8) s[1];
        ul = (ul<<8) + (U8) s[2];
        ul = (ul<<8) + (U8) s[3];
    }
    return (ul);
}
/***************************************************************************
*                                                                          *
*  UngetOneByte - Get one byte from load buffer                            *
*  parameter :                                                             *
*       None                                                               *
*  return value :                                                          *
*       1  ---  OK                 0  ---  0                        *
***************************************************************************/
BOOL CLdrSvr::UngetOneByte()
{                                        
    if ( 1 != SeekLoadFile(-1L,1) ) return 0;
    return 1;
}
    
/***************************************************************************
*                                                                          *
*  GetOneByte - Get one byte from load buffer                              *
*  parameter :                                                             *
*       ch  --  byte pointer ( output )                                    *
*  return value :                                                          *
*       0  ---  OK                 -1  ---  0                        *
*                                                                          *
***************************************************************************/
BOOL CLdrSvr::GetOneByte(U8 *ch)
{                                   
    if (m_uBufPos < m_uBufSize) {
        *ch = m_lpBuffer[m_uBufPos];
        m_uBufPos++;
    }
    else {              
        m_uBufInFilePos += m_uBufSize;
        m_uBufSize = (U16)_lread(m_hLdrFile , m_lpBuffer , LDR_BUFSIZE);
        if ( m_uBufSize == 0 ) return( 0 );
        *ch = *m_lpBuffer;
        m_uBufPos = 1;
    }   
    return 1;
}

/***************************************************************************
*                                                                          *
*  PeekByte - Peek one byte from load buffer                              *
*  parameter :                                                             *
*       ch  --  byte pointer ( output )                                    *
*  return value :                                                          *
*       1  ---  OK                 0  ---  failure                         *
*                                                                          *
***************************************************************************/
BOOL CLdrSvr::PeekByte(U8 *ch)
{                                   
    if (m_uBufPos < m_uBufSize) {
        *ch = m_lpBuffer[m_uBufPos];
    }
    else {              
        m_uBufInFilePos += m_uBufSize;
        m_uBufSize = (U16)_lread(m_hLdrFile , m_lpBuffer , LDR_BUFSIZE);
        if ( m_uBufSize == 0 ) return 0;
        *ch = *m_lpBuffer;
        m_uBufPos = 0;
    }   
    return 1;
}
    
/***************************************************************************
*  GetBytes - Get n byte from load buffer                                  *
*  parameter :                                                             *
*       ch  --  byte pointer ( output )                                    *
*       num  --  byte number ( input )                                     *
*  return value :                                                          *
*       1  ---  OK                 0  ---  0                        *
***************************************************************************/
BOOL CLdrSvr::GetBytes(U8 *ch , U32 num)
{                                   
    U32 i , j;
    U8 *temp;
    
    temp = ch;
    i = 0;
    while ( i < num ) {
        if (m_uBufPos >= m_uBufSize) {
            m_uBufInFilePos += m_uBufSize;
            m_uBufSize = (U16)_lread(m_hLdrFile , 
                            m_lpBuffer , LDR_BUFSIZE);
            if ( m_uBufSize == 0 ) return(0);
            m_uBufPos = 0;
        }
        j = m_uBufSize - m_uBufPos;
        j = ( j > (num - i) ) ? (num - i) : j;
        memcpy( &ch[i] , &m_lpBuffer[m_uBufPos] , (U16)j);
        i += j;
        m_uBufPos += (U16) j;
    }        
    return 1;
}
 
void CLdrSvr::Error(U32 ulErrCode, U32 ulRecCode)
{
#ifdef _DUMP_
	OutError( ulErrCode, ulRecCode);
#else
    if ( LOAD_WARNING(m_nLdrOptFlag) )
         OutError( ulErrCode, ulRecCode);
#endif
}

/***************************************************************************
*                                                                          *
*  OutError - Show error infomation                                        *
*  parameter :                                                             *
*       ulErrCode  --  error code                                           *
*       ulRecCode  --  recovery code                                        *
*  return value :                                                          *
*       None                                                               *
*                                                                          *
***************************************************************************/
void CLdrSvr::OutError(U32 ulErrCode, U32 ulRecCode)
{
	CString strErr, strRec;
	U32 rtn;       
	
    if (m_where == LOAD_FROM_SHELL ) {
        rtn=ErrGetErrorText(ulErrCode, ulRecCode, strErr, strRec);
        DLLLdrShowLine((LPSTR)(LPCSTR)strErr);
        if(ulRecCode) DLLLdrShowLine((LPSTR)(LPCSTR)strRec);                           
    }
    else ErrDisplayError(ulErrCode, ulRecCode );
}

void CLdrSvr::Error(char * str)
 {
    CString strError ;
    
    strError = LPSTR(str);
    if (m_where == LOAD_FROM_SHELL) {
        if ( LOAD_WARNING(m_nLdrOptFlag)){
             DLLLdrShowLine(str);
             return;
        }                            
    }
    else{ 
        if (LOAD_WARNING(m_nLdrOptFlag)){
            AfxMessageBox(strError);
            return;
        }
    }
 }                                
/***************************************************************************
*  Message - Show dump infomation                                       *
*  parameter :                                                             *
*       format  --  information format string                                *
*  return value :                                                          *
*       None                                                               *
***************************************************************************/
void CLdrSvr::Message(char *format,...)
{
	char Str[256];
   	va_list marker;
   	va_start( marker, format );     /* Initialize variable arguments. */
	wvsprintf(Str,format,marker);
	va_end( marker );
#ifdef _DUMP_
    DLLLdrShowLine(Str);
#else
    if ( m_where == LOAD_FROM_SHELL ) {
         DLLLdrShowLine(Str);
    }
    else {
        AfxMessageBox(Str);
    }
#endif
}

 
void CLdrSvr::DisplayErrorRecord(U32 errorStartPos)
{
	U32 fCurPos = GetFileCurPos();
	if(SeekLoadFile(errorStartPos,SEEK_SET) == 0 ) 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) == 0 ) {
		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;
}


BOOL CLdrSvr::CloseModToSym() 
{
  int symFlag;
  RETCODE retCode;
  
  retCode = 0;
  symFlag = LOAD_SYM(m_nLdrOptFlag);
  if(!symFlag){
     return 1;
  }

  QUAL_ADDR_RANGE_TYPE qaddr;
  m_modNode.codeaddr.segType = ( SEGMENTTYPE ) SEG_CODE;
  m_modNode.codeaddr.startAddr = m_uStart;
  m_modNode.codeaddr.endAddr = m_uEnd;
  qaddr.startAddr = m_uStart;
  qaddr.endAddr = m_uEnd;
  qaddr.startValid = TRUE;
  qaddr.endValid = TRUE;                      
  if (m_uStart > m_uEnd ) {
      qaddr.startValid = FALSE;
      qaddr.endValid = FALSE;
  }
#ifndef _LONG_ 
  if (symFlag && m_modNode.linecnt > 0 ) {
      retCode = SymAddLinenumEnd();
      if(retCode != 0 ) {
        m_dwErrMsg = ER_LDR_SYM_SERVER;
         return(0);
      }
  }
  retCode = SymAddModuleClose((BOOLEAN) (TRUE));
  if ( retCode != 0 ) {
       m_dwErrMsg = ER_LDR_SYM_SERVER;	
       return(0);
  }
  if ( qaddr.startValid || qaddr.endValid ){
       retCode = SymAddSymbolSetAddr( &qaddr );
       if ( retCode != 0 ) {
            m_dwErrMsg = ER_LDR_SYM_SERVER;
            return(0);
       }
  }
#endif
  ClearUpModuleBlock();
  return 1;              
 }  //end of function

 void CLdrSvr::ConvertAddrToBank(U32& addr)
 {
    addr |= (U32(m_nLoadToBank-1)<<16);
 } 
          
/////////////////////////////////////////////////////////////////////////////

